これは未定義の動作ですか?-128
結果として出力されます。
#include<stdio.h>
int main()
{
char i=-128;
i=-i;
printf("%d",i);
}
説明してください。
これは未定義の動作ですか?-128
結果として出力されます。
#include<stdio.h>
int main()
{
char i=-128;
i=-i;
printf("%d",i);
}
説明してください。
8 ビット符号付き値の -128 の 2 の補数は -128 です。
バイナリ値を見てください。
元の値: 10000000
補足: 01111111
増分: 10000000
これは未定義の動作ではありません。タイプがプラットフォームで署名されていると仮定するとchar
、それは実装定義の動作です。(C99、6.3.1.3p3)
i = -i
;
i
inは最初に-i
に昇格され、int
次に整数変換によって に変換されます。-i
128
128
char
128
への変換char
は実装定義であると述べている標準の段落は次のとおりです。
(C99, 6.3.1.3p3) それ以外の場合、新しい型は署名されており、値を表現できません。結果が実装定義であるか、実装定義のシグナルが発生します。
EDIT : 実装定義ですが、ほとんどの実装間で共通の実装動作があります。gcc
ドキュメントが行うべきこと(および他のほとんどのコンパイラが行うこと) は次のとおりです。
幅 N の型への変換の場合、値は型の範囲内になるように 2^N を法として減らされます。信号が発生しない
http://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html
すべてのコンパイラがこのように動作するわけではないことに注意してください。一部の (DSP) コンパイラは飽和状態になります。この場合 (そしてまだ signed を想定しているchar
)、i = -i;
の値の後は にi
なります127
。
-128 = 0b10000000
だからあなたは見つけたい: -(-128):
~(-128) = 0b01111111
0b01111111 + 0b1 = 0b10000000 = -128
したがって、8 ビットの数値では、-(-128) = -128!
あなたは署名された文字を使用しています。符号付きの正の 1 バイトの最大値は 127 です。-128 を否定して +128 にしようとすると、-128 にオーバーフローしてしまいます。この動作は、OS とコンパイラに依存している可能性があります。
未定義の動作ではありません。
-1 による乗算は、ビットを否定してから 1 を加算することと同じです。
~10000000+1 = 01111111+1 = 10000000
まだ-128
です。
同じ結果が得られます。
アセンブリは次のとおりです (Microsoft Visual Studio):
; File tmp.c
; Line 5
push ebp
mov ebp, esp
push ecx
; Line 6
mov BYTE PTR _i$[ebp], -128 ; ffffff80H
; Line 7
movsx eax, BYTE PTR _i$[ebp]
neg eax
mov BYTE PTR _i$[ebp], al
; Line 8
movsx ecx, BYTE PTR _i$[ebp]
push ecx
push OFFSET FLAT:$SG775
call _printf
add esp, 8
; Line 9
xor eax, eax
; Line 10
mov esp, ebp
pop ebp
ret 0
_main ENDP
バイナリ値に注意してください。
そして、「2 の補数」演算を覚えておいてください。
それは理にかなっていますか?
====== 補遺 ======
これは本当に簡単です。明確にするのに役立つかもしれないわずかに変更された例を次に示します。
#include <stdio.h>
int
main (int argc, char *argv[])
{
int i=-128, j, k, l;
char c = i;
printf("i: %d == 0x%x; c: %d == 0x%x\n", i, i, c,c);
j=-i;
k=~i;
l=0-i;
i=-i;
c=-c;
printf("%d, %d, %d, %d, %d\n",i,j,k,l,c);
printf("0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",i,j,k,l,c);
return 0;
}
結果:
i: -128 == 0xffffff80; c: -128 == 0xffffff80
128, 128, 127, 128, -128
0x80, 0x80, 0x7f, 0x80, 0xffffff80