問題: d=1,-d==?
我們看看答案會是什麼樣的:
-----------------------------
下面的代碼的 輸出是什麼?
int main() {
char dt = '\1';
long tdt;
tdt = -dt;
printf("%ld\n", tdt);
}
我的第一反應是這個輸出應該是”-1“。 我想你也是這樣認為的。然而如果在64位系統上輸出是什麼 呢?我期望也是”-1“。 我們看看是這樣的嗎。
讓我們測試一下。
#xlc -q64 a.c - qlanglvl=extended
#./a.out
4294967295
!! 這裡的輸出是“4294967295” 而不是“-1”,怎麼會這 樣呢?
別急別急,可能是我們漏了什麼?
在回答之前上面問題之前,我們看看下面代碼段:
"char dt = '\1'; -dt;"
對於這個代碼段,我們確認一下dt變量是有符號還是沒有符號的?C
我們看看C語言標准怎麼說的:
The implementation shall define char to have the same range, representation, and behavior as either signed char or unsigned char.
也就是說標准沒有對char類型變量的符號做要求。我們在看看XL 編譯器的文檔 http://publib.boulder.ibm.com/infocenter/comphelp/v111v131/topic/com.ibm.xlc111.aix.doc/language _ref/ch.html
裡面說:
By default, char behaves like an unsigned char. To change this default, you can use the -qchars option or the #pragma chars directive. See -qchars for more information.
看來XL編譯器中,char默認是無符號的。我們可以用-qchars來改變這個默認行為。我們來測 試一下:
#xlc -q64 a.c -qlanglvl=extended -qchar=signed
#./a.out
-1
太好了,原來如 此。我們好像明白了。
不要急,現在都講究Hold住。你真的明白了嗎?可能還沒有。 我們看另一個問題:
不用-qlanglvl=extended也可以得到“-1”,不管用不用-qchars, 為什麼呢?如下:
-------------
#xlc -q64 a.c
#./a.out
-1
--------------
並且,下面的代碼也打印“-1”,即使使用- qlanglvl=extended:
--------------
int main() {
unsigned char dt = '\1';
long tdt =dt;
tdt = -tdt;
printf("%ld\n", tdt);
}
#xlc -q64 a.c -qlanglvl=extended ;./a.out
-1
--------------
為什麼下面的代碼 的輸出又成了 "4294967295"?
int main() {
unsigned dt = '\1';
long tdt;
tdt = -dt;
printf("%ld\n", tdt);
}
這裡面似乎有一些深層的東西,我們來仔細看看下面幾點:
* 減號操作符的行為
* 整數提升的 規則 ( integral promotion)
* 類型轉換 (type cast)
########################################
我們一個一個來看:
1. 減號操作符的行為: ISO C++ 標准說
The result of the unary - operator is the negative of its (promoted) operand. The integer promotions are performed on the operand, and the result has the promoted type.
因此減 號操作符的運算結果類型依賴於操作數被提升之後的類型。
在XL編譯器的文檔中,也有類似的說法:
http://publib.boulder.ibm.com/infocenter/comphelp/v111v131/topic/com.ibm.xlc111.aix.doc/langu age_ref/artnege.html
Unary minus operator - :The result has the same type as the operand after integral promotion.
2. 整數提升的規則
在XL文檔中我們看到下面的信息
http://publib.boulder.ibm.com/infocenter/comphelp/v111v131/topic/com.ibm.xlcpp111.aix.doc/lan guage_ref/integer_float_promotion.html?resultof=%22%70%72%6f%6d%6f%74%65%64%22%20%22%70%72%6f% 6d%6f%74%22%20
If an integer type other than wchar_t, bit field, and Boolean can be represented by the int type and its rank is lower than the rank of int, the integer type can be converted to the int type. Otherwise, the integer type can be converted to the unsigned int type.
同時我們注意到XL的下面說明:
*****************************************************************
-qupconv (C only)
Specifies whether the unsigned specification is preserved when integral promotions are performed.
Defaults
-qnoupconv for all language levels except classic or extended
-qupconv when the classic or extended language levels are in effect
***********************************************************
可以看出選項-qupconv(- qlanglvl=extended)影響了整數提升時對符號位的處理行為。指定-qlanglvl=extended或-qupconv時保留符 號位進行整數提升。
3. 我們知道在強制類換類型是符號位取決於目標類型。
由此,我們回過頭來看看 上面的代碼:
----------------------
int main() {
unsigned char dt = '\1';
long tdt =dt; //類型強制轉換 tdt 的仍然是”1“
tdt = -tdt; //結果類型仍然是 long, 因此結果是 -1
printf("%ld\n", tdt);
}
--------------------------
對於
int main() {
unsigned dt = '\1';
long tdt;
tdt = -dt; ///==等價於 => (long)( (unsigned int) (-((unsigned int)u)) )
printf("%ld\n", tdt);
}
dt類型是 unsigned int ,不需要 (根據上面的第2條)提升, 因此 "-dt" 的類型仍然 是"unsigned int". 所以-dt 的值就是"0xFFFFFFFF" (在二進制上看),然後強 制轉換成long類型並付給dt;因此 0x00000000FFFFFFFF的結果是4294967295。
對於
int main() {
unsigned char dt = '\1';
long tdt;
tdt = -dt;
printf("%ld\n", tdt);
}
tdt = -dt; unsigned char首先需要提升,提升成為"unsigned int" 如 果-qupconv或-qlanglvl=extended;否則提升成“int”
因此-qupconv/-qlanglvl=extended時:tdt=-dt 等價於to "(long)( (unsigned int) (-((unsigned int)td)) )" 。從而結果是4294967295
在 -qnoupconv(其他langlvl)時等價於"(long)( ( int) (-(( int)dt)) )" 結果是-1。
至此,我 們終於能過回答“d=1,-d==?”了。其結果依賴於被操作數的類型,可能發生的的類型轉換以及編譯器選項。