2016-11-21 18 views
0

なぜこのコードは32768ではなく-32768を出力しますか?オーバーフローのように見えますが、私はどこを見つけることができません。C不思議なオーバーフロー

#include <stdio.h> 
#include <stdlib.h> 
int main() 
{ 
    char *buffer = (char*)malloc(sizeof(char)*2); 
    buffer[0] = 0x80; 
    buffer[1] = 0x00; 
    int address = (buffer[0]<<8) | (buffer[1]); 
    printf("%d\n", address); //outputs -32768 
    return 0; 
} 
+3

バッファは[0]ですので-128 – immibis

+0

ああすごいことをする必要があります符号なしのはずのそれ – danielmhanover

+0

"int"は符号付きの数値です。上位ビットが符号付き整数に設定されている場合は、負であることを示します。おそらく、あなたはGoogleの "2の補完"をする必要があります。 – TonyB

答えて

1

charに署名されています。

コンパイラで0x80はに変換され、符号付きcharに収まるように変換されます。

したがってbuffer[0]は-128を保持し、((-128)<<8) | (0)は-32768と評価します。

+0

'( - 128) "8"は未定義の動作を評価します。 – Lundin

0

このコードを実行する方法はいくつかあります。

  • charは、コンパイラでは符号なしです。式は0x80<<8 | 0x00と評価され、0x8000となります。これがシステムのintに収まる場合、結果は32768になります。そうでない場合は、実装定義の方法で符号付き形式に変換されます。 2の補数の計算機では、結果は-32768になるでしょう。

  • charは、コンパイラで署名されています。それで0x80はその内部に収まることはできませんが、実装定義の方法では負の数に変換されます。 2の補数のコンピュータでは、おそらく値-128を得るでしょう。この負の値をシフトした後、の定義されていない動作(ソース:C11 6.5.7/4)を呼び出します。その結果、何かが起こる可能性があります。あなたのプログラムはクラッシュしたり、ナンセンスを出力したり、-32768のように結果を扱うなど、特定の非標準的な動作がコンパイラに存在する可能性があります。

重要な点は、このようなコードを書くことは避けてください。このようなコードは、さまざまな形式の動作が不適切であることに依存しています。それは悪い習慣です。 charintのようなCのネイティブのプリミティブなデータ型を使用しているため、ビット操作に使用するのが危険なため、これで終わります。

あなたのコードでは、決定論的結果に関係なくシステムやコンパイラを与えないだろう安全な何か、に固定しなければならない

#include <stdio.h> 
#include <stdlib.h> 
#include <stdint.h> 
#include <inttypes.h> 

int main() 
{ 
    uint8_t *buffer = malloc(sizeof(uint8_t[2])); 
    buffer[0] = 0x80; 
    buffer[1] = 0x00; 
    uint16_t address = ((uint16_t)buffer[0]<<8) | (buffer[1]); 
    printf("%" PRIu16 "\n", address); 
    free(buffer); 
    return 0; 
}