The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with
zeros. If E1 has an unsigned type, the value of the result is E1 × 2E2, reduced modulo
one more than the maximum value representable in the result type. If E1 has a signed
type and nonnegative value, and E1 × 2E2 is representable in the result type, then that is
the resulting value; otherwise, the behavior is undefined.
英文不太好看, 大概是這樣的意思, 1 << 31 是 0x80000000 int 無法存入這個數值, 所以是 undefined behavior, unsigned int 才能存 0x80000000。
使用 -m32 是因為 long 在 linux 64/32 會有不同的解釋, 先用 linux 32 環境為主來觀察。0xffffffff 是 unsigned int, 如果 0xffffffff + 1 之後, type 會是 long long unsigned int 或是 long long int 嗎?
linux man page 提到: For input streams associated with seekable files (e.g., disk files, but not pipes or terminals), 也許 stdin 不算是 seekable files 吧! 所以 fflush(stdin) 無效。另外「C程式語言」B-4 提到 fflush 對於 input streams, 結果未定義 (undefined behavior)。
-2147483648 可以用 int 大小 (32bit) 裝下, 0x80000000 是其 16 進位表達式。
2147483648 卻要用 long long 大小 (64bit) 才能裝下, 0x0000000080000000 是其 16 進位表達式。
descent@debian64:ctrl_proc$ g++ -m32 -Wall -std=c++11 int.cpp -o int
int.cpp: In function ‘int main(int, char**)’:
int.cpp:12:29: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long long int’ [-Wformat=]
printf("%d\n", -2147483648);
^
int.cpp:10:7: warning: unused variable ‘i’ [-Wunused-variable]
int i = -2147483648;
^
descent@debian64:ctrl_proc$ ./int |c++filt -t
long long
-2147483648
-2147483648 type 是 long long, 而不是 int, 雖然 int 裝的下 -2147483648, 怎麼回事, 從 AST 來看這個 printf("%d\n", -2147483648); 運算式。
-2147483648 被分成 -, 2147483648, 而 2147483648 是 long long type, 做了 - 運算後, 依然是 long long, 所以 -2147483648 是 long long, 也就是 0xffffffff80000000, 而 %d 預期是 int type, 所以編譯器便發出 warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long long int’ [-Wformat=] 警告。
有趣的是 int.cpp L10, int i = -2147483648; 卻不會發警告, int i 是可以存進 -2147483648, 真奇怪, -2147483648 的 type 是 long long, 所以會有被截掉的可能, 但是由於 -2147483648 可以裝進 int, 所以不用擔心會被截掉。
如果你對《inux c 編程 一站式學習》這本書寫的有懷疑, 又看不懂 c spec, the c programming language 繁體中文版 A6.5 也介紹了 usual arithmetic conversions 的規則, 寫的不是很詳細, 不過對照程式應該可以看懂為什麼是符合該轉換規則。