簡體   English   中英

C 如何將未簽名轉換為已簽名?

[英]How does C casting unsigned to signed work?

標准中的哪種語言使此代碼有效,打印“-1”?

unsigned int u = UINT_MAX;
signed   int s = u;
printf("%d", s);

https://en.cppreference.com/w/c/language/conversion

否則,如果目標類型已簽名,則行為是實現定義的(可能包括發出信號)

https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation

  • GCC 只支持二進制補碼 integer 類型,所有位模式都是普通值。

  • 當值不能在該類型的 object 中表示時,將 integer 轉換為帶符號的 integer 類型的結果或引發的信號(C90 6.2.1.2、C99 和 C11 6.3.1.3):

    為了轉換為寬度為 N 的類型,該值將以 2^N 為模減少到該類型的范圍內; 沒有發出信號。

對我來說,將UINT_MAX轉換為int似乎意味着將UINT_MAX除以2^(CHAR_BIT * sizeof(int)) 為了爭論,對於 32 位整數, 0xFFFFFFFF / 2^32 = 0xFFFFFFFF 所以這並不能真正解釋值 '-1' 是如何在int中結束的。

其他地方是否有某種語言說在模除法之后我們只是重新解釋這些位? 或者在我引用的部分之前優先的標准的其他部分?

C 標准的任何部分都不能保證您的代碼通常會打印 -1。 正如它所說,轉換的結果是實現定義的。 但是,GCC 文檔確實 promise 如果您使用它們的實現進行編譯,那么您的代碼將打印 -1。 這與位模式無關,只是數學。

GCC 手冊中“reduced modulo 2^N”的明確意圖是,結果應該是signed int范圍內的唯一數字,它與輸入一致 mod 2^N。 這是定義您期望的“包裝”行為的精確數學方法,這恰好與您通過重新解釋位得到的結果一致。

假設為 32 位, UINT_MAX的值為 4294967295。這與 4294967296 與 -1 的模一致。 即4294967295與-1之差是4294967296的倍數,即4294967296本身。 此外,這必然是 [-2147483648, 2147483647] 中唯一的此類數字。 (與 -1 一致的任何其他數字至少為-1 + 4294967296 = 4294967295 ,或至多為-1 - 4294967296 = -4294967297 )。 所以-1是轉換的結果。

換句話說,重復添加或減去 4294967296,直到您得到一個在signed int范圍內的數字。 保證只有一個這樣的數字,在本例中為 -1。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM