c語言裡面TMin不能寫成-2147483648的原因
C語言中,將TMin(32位有符號整數的最小值)寫成 -2147483647-1,而不是簡單地寫成 -2147483648 或 0x80000000 。這是為什麼呢?
首先,對於整數常量的定義:
An integer constant begins with a digit, but has no period or exponent part. It may have a prefix that specifies its base and a suffix that specifies its type.
可見如果不發生溢位,整型常量的值總是非負數。如果前面出現符號,則是對整型常量使用的一元運算子,而不是整型常量的一部分。整型常量的實際型別取決於長度、基數、字尾字母和C語言實現確定的型別表示精度。具體的根據表一來確定。
其次
#define INT_MAX 2147483647
#define INT_MIN (-INT_MAX - 1)
那麼考慮到以上兩點,如果將TMin32寫成-2147483648並且將程式碼在一個32位的機器上面編譯,當編譯器遇到-X形式的數值,它首先會確定X的資料型別和值,然後取X的。
ISO C90 | ISO C99 | ||
十進位制(Decimal) | 十六進位制(Hexadecimal) |
十進位制(Decimal) | 十六進位制(Hexadecimal) |
int long unsigned unsigned long |
int
unsigned
long
unsigned long |
int long long long | int unsigned long unsigned long long long unsigned long long |
表一 根據C語言版本和常量的格式(十進位制和十六進位制),常量的資料型別是從上面表格裡選擇第一個合適(能表示常量)的型別。
Word Size | ISO C90 | ISO C99 | ||
Expression | -2147483648 | 0x80000000 | -2147483648 | 0x80000000 |
32 64 | unsigned long | unsigned unsigned | long long long | unsigned unsigned |
表二 根據C語言版本和常量的格式(十進位制和十六進位制),可以為這兩個表示式得到三種不同的資料型別,包括資料為正值的情況。
由於2147483648超過了int所能夠表示的範圍,編譯器就會再次選擇一種可以正確的表示此值的型別。然後它就會按照第一個表格(十進位制)的順序往下繼續嘗試型別,再假設編譯器採用的標準是ISO C90,int->long->unsigned,然後就發現unsigned是第一個合適的資料型別。正如我們知道的,2147483648和-2147483648在32位數值上擁有同樣的位表示,使得此常量的最終資料型別是unsigned且值為2147483648。這對於16進位制的0x80000000也是相同的結果。
對於64位來說十進位制和十六進位制會分別選擇long(-2147483648)和unsigned(2147483648)。而ISO C99的情況則是按照上述規則資料型別為long long才能容納2147483648。
最後結論是:-214748364832位機器裡使用ISO C90進行編譯,會先將2147483648看成是一個unsigned,再對2147483648進行無符號的加法逆元計算(見csapp第二版56頁),得到結果是:
(-uw2147483648) = 2w - x = 232 - 231 = 231 = 2147483648。
所以對於下面的表示式:
int result = -2147483648 < 2147483647;
在32位機器裡面使用ISO C90進行編譯, result = 0。