[英]In C programming Language: What order would 3 (Number 3) be assigned to the variables? As in which variable would receive 3 first, second and third?
[英]What is the algorithm that a compiler would use while casting signed variables to larger variable types, C language?
答案可能取決於編譯器,但是;
以下行的預期 output 是什么?
signed char a = -5;
printf("%x \n", (signed short) a);
printf("%x \n", (unsigned short) a);
編譯器會在將signed char
轉換為更大的變量時用零 (0) 或一 (1) 填充最高有效位嗎? 如何以及何時?
PS 還有其他問題。 我試圖在在線編譯器上運行下面的代碼進行測試。 結果並不像我預期的那樣。 所以我添加了詳細的轉換,但它沒有用。 為什么printf("%x \n", (signed char)b);
的output是 4 個字節長而不是 1 個字節?
int main()
{
unsigned char a = (unsigned char)5;
signed char b = (signed char)-5;
unsigned short c;
signed short d;
c = (unsigned short)b;
d = (signed short)b;
printf("%x ||| %x ||| %x ||| %x\n", (unsigned char)a, (signed char)b, c, d);
printf("%d ||| %d ||| %d ||| %d\n", a, b, c, d);
printf("%d ||| %d ||| %d ||| %d\n", a, b, (signed char)c, (signed char)d);
return 0;
}
Output:
5 ||| fffffffb ||| fffb ||| fffffffb
5 ||| -5 ||| 65531 ||| -5
5 ||| -5 ||| -5 ||| -5
在 C 中,arguments 到等級低於int
的可變參數函數(如printf
)被轉換為int
。 (不是unsigned int
除非參數是無符號的並且寬度與int
相同)。
將signed short
或signed char
轉換為signed int
不會更改值。 如果您從 -5 開始,您將以 -5 結束。
但是,如果您將負符號值轉換為無符號類型(例如,使用顯式強制轉換),則轉換將以比無符號類型的最大值大一為模的方式完成。 例如, unsigned short
的最大值為 65535(在許多實現中),因此將 -5 轉換為unsigned short
結果為 -5 模 65536,即 65531。(C 的%
運算符不產生數學模歸約。)當那個然后 value 被隱式轉換為int
,它仍然是 65531,所以這就是用%x
( fffb
) 打印的內容。
請注意,將格式%x
應用於signed int
在技術上是不正確的。 %x
要求相應的參數是一個unsigned int
。 目前,C 不保證將有符號值解釋為無符號值的結果是什么,但這很快就會改變。 (這不是轉換。在運行時,類型不再存在,值只是位模式。)
在C11 標准的第 6.3.1.3 節中列出了在有符號和無符號類型之間轉換的確切規則:
1當 integer 類型的值轉換為
_Bool
以外的另一種 integer 類型時,如果該值可以用新類型表示,則它不變。2否則,如果新類型是無符號的,則通過比新類型可以表示的最大值重復加或減一來轉換值,直到該值在新類型的范圍內。
3否則,新類型已簽名,無法在其中表示值; 結果是實現定義的,或者引發了實現定義的信號。
至於上面這段代碼的含義:
signed char a = -5;
printf("%x \n", (signed short) a);
printf("%x \n", (unsigned short) a);
這里發生了一些事情。
對於第一個printf
,您首先將signed char
轉換為signed short
。 根據上面的第 1 條,由於值 -5 可以存儲在兩者中,因此值不會被強制轉換更改。 然后,因為這個值被傳遞給可變參數 function,所以它被提升為int
類型,並且再次通過第 1 條,該值保持不變。
然后使用%x
格式說明符打印生成的int
值,該說明符需要一個unsigned int
。 對於不匹配的格式說明符,這在技術上是未定義的行為,盡管大多數實現將允許隱式簽名/未簽名重新解釋。 因此,假設二進制補碼表示,將打印int
值 -5 的表示,並假設 32 位int
這將是fffffffb
。
對於第二個printf
,從signed char
到unsigned short
的轉換將根據上面的第 2 條發生,因為值 -5 不能存儲在unsigned short
中。 假設 16 位短,這給你值 65536 - 5 = 65531。假設兩個補碼表示,這相當於將表示從fb
符號擴展到fffb
。 這個unsigned short
值然后在傳遞給printf
時被提升為int
,並且根據第 1 條,該值保持不變。 然后%x
格式說明符將其打印為fffb
。
當被轉換的值可以在目標類型中表示時,integer 類型之間的轉換是值保留的。 signed short
可以表示signed char
可表示的所有值,所以這...
signed char a = -5;
printf("%hd\n", (signed short) a);
...預計 output 包含“-5”的行。
但是,您的代碼具有未定義的行為。 轉換說明符%x
要求相應的參數具有類型unsigned int
,而您傳遞的是帶signed short
(根據默認參數促銷轉換為int
)。
如果您的實現對有符號整數使用二進制補碼表示(我可以肯定地斷言它確實如此),則表示會將原始帶signed char
符號擴展為帶signed short
的寬度,然后將其符號擴展為(signed) int
的寬度。 因此,UB 在您身上的一種合理可能的表現形式……
printf("%x \n", (signed short) a);
...將是打印
fffffffb
另一種情況有點不同。 Integer 目標類型為無符號且不能表示源值的轉換已明確定義。 通過以目標類型中可表示值的數量為模減少源值,將源值轉換為目標類型。 因此,如果您的unsigned short
有 16 個值位,那么將 -5 轉換為unsigned short
的結果是 -5 modulo 65536,即 65531。
因此,
printf("%hu\n", (unsigned short) a);
預計會打印包含“65531”的行。
同樣, %x
轉換說明符與相應參數的類型不匹配( (unsigned short) a
,通過默認參數提升轉換為int
),因此您的printf
具有未定義的行為。 但是,在二進制補碼系統上將 16 位unsigned short
轉換為 32 位int
將涉及零擴展源的表示形式,因此 UB 在您的...
printf("%x \n", (unsigned short) a);
...將是打印
fffb
.
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.