[英]Type of integer literals and ~ in C
我是C初學者,我對C答案書中的以下示例感到困惑。
在系統中查找unsigned long long大小的一種方法是鍵入:
printf("%llu", (unsigned long long) ~0);
我不知道為什么這個語法有效?
在我的系統上, int
是32位, long long
是64位。
我所期望的是,因為0
是整數類型的常量,所以~0
計算32位整數的否定,然后由unsigned long long
轉換運算符將其轉換為unsigned long long
整數。 結果應該給出2 32 - 1。
不知何故,看起來~
運算符已經知道它應該作用於64位?
編譯器是否將此指令解釋為printf("%llu", ~(unsigned long long)0);
? 這聽起來不對,因為演員和~
具有相同的優先權。
不知何故,看起來〜運算符已經知道它應該作用於64位?
它不是~
運算符,它是演員。 以下是根據標准完成整數轉換的方法:
6.3.1.3有符號和無符號整數
- 當具有整數類型的值轉換為除_Bool之外的另一個整數類型時,如果該值可以由新類型表示,則它將保持不變。
- 否則,如果新類型是無符號的,則通過重復地添加或減去一個可以在新類型中表示的最大值來轉換該值,直到該值在新類型的范圍內。
- 否則,新類型將被簽名,並且值無法在其中表示; 結果是實現定義的,或者引發實現定義的信號。
signed int
~0
的值對應於具有負值的二進制補碼表示的系統上的-1
。 它不能用unsigned long long
,因此第一個要點不適用。
第二個要點確實適用:新類型是無符號的,因此unsigned long long
MAX
被加到-1
一次,以使結果進入unsigned long long
的范圍。 這與符號擴展-1
到64位具有相同的效果。
0
的類型為int
,而不是unsigned int
。 因此, ~0
(在使用二進制補碼整數表示的機器上,這是今天使用的所有機器)將為-1,而不是2 32 - 1。
假設一個64位unsigned long long
, (unsigned long long) -1
是-1
模2 64 ,即2 64 - 1。
0
是一個int
~0
仍然是一個int
,即值-1
。
將int
為unsigned long long
只是為了匹配printf期望的類型與轉換llu
。
但是,-1的值擴展為無符號長long,對於4字節int應為0xffffffff,對於8字節int應為0xffffffffffffffff。
根據N1570委員會草案:
6.5.3.3一元算術運算符
- 〜運算符的結果是其(提升的)操作數的按位補碼 (即,當且僅當未設置轉換后的操作數中的相應位時,才會設置結果中的每個位)。 整數提升在操作數上執行,結果具有提升類型。 如果提升類型是“ 無符號類型 ,則表達式~E等於該類型中可表示的最大值減去E”。
§6.2.6.2語言45 :
(補充)。 其中的哪一個適用於實現定義 ,符號位為1且所有值位為零的值(對於前兩個),或者符號位和所有值位1(對於補碼)是否為陷阱表示或正常值。 在符號和幅度以及1'補碼的情況下,如果該表示是正常值,則稱為負零。
因此,代碼的行為:
printf("%llu", (unsigned long long) ~0);
在某些機器上實現定義和未定義 - 不是按預期 - 依賴於機器中整數的內部表示。
根據6.5.3.3節,批准的編寫代碼的方式是:
printf("%llu", (unsigned long long) ~0u);
此外, ~0u
類型是unsigned int,當你將它轉換為unsigned long long int
時,格式字符串是llu
。 使用格式字符串%u
打印~0u
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.