[英]Wrap around explanation for signed and unsigned variables in C?
我在C規范中讀到一點,無符號變量(特別是unsigned short int
)在整數溢出上執行一些所謂的回繞 ,雖然除了我留下未定義的行為之外我找不到任何有符號的變量。
我的教授告訴我他們的價值觀也被包圍了(也許他只是意味着gcc)。 我以為這些位被截斷了,我留下的位給了我一些奇怪的價值!
什么是環繞的,它與截斷位有什么不同。
有符號整數變量在C語言中沒有環繞行為。 算術計算期間的有符號整數溢出會產生未定義的行為 。 請注意,您提到的GCC編譯器在優化中實現嚴格溢出語義是已知的,這意味着它利用了這種未定義行為情況提供的自由:GCC編譯器假定有符號整數值永遠不會回繞。 這意味着GCC實際上恰好是您不能依賴有符號整數類型的環繞行為的編譯器之一。
例如,GCC編譯器可以假設對於變量int i
具有以下條件
if (i > 0 && i + 1 > 0)
相當於一個人
if (i > 0)
這正是嚴格溢出語義的含義。
無符號整數類型實現模運算。 模數等於2^N
,其中N
是類型的值表示中的位數。 因此,無符號整數類型確實似乎在溢出時回繞。
但是,C語言從不在小於int
/ unsigned int
域中執行算術計算。 您在問題中提到的類型unsigned short int
通常會在任何計算開始之前被提升為表達式中的int
類型(假設unsigned short
的范圍適合int
的范圍)。 這意味着1)使用unsigned short int
的計算將在int
的域中執行,當int
溢出時發生溢出,2)在這樣的計算期間溢出將導致未定義的行為,而不是環繞行為。
例如,此代碼生成環繞
unsigned i = USHRT_MAX;
i *= INT_MAX; /* <- unsigned arithmetic, overflows, wraps around */
而這段代碼
unsigned short i = USHRT_MAX;
i *= INT_MAX; /* <- signed arithmetic, overflows, produces undefined behavior */
導致未定義的行為。
如果沒有發生int
溢出並且結果被轉換回unsigned short int
類型,則它再次以模2^N
減少,這將看起來好像值已經被包圍。
想象一下,你的數據類型只有3位寬。 這允許您表示8個不同的值,從0到7.如果添加1到7,您將“回繞”回到0,因為您沒有足夠的位來表示值8(1000)。
對於無符號類型,此行為已明確定義。 它沒有為簽名類型定義良好,因為有多種方法可以表示有符號值,並且溢出的結果將根據該方法進行不同的解釋。
符號幅度:最高位表示符號; 0表示正數,1表示負數。 如果我的類型再次是三位寬,那么我可以表示如下的有符號值:
000 = 0
001 = 1
010 = 2
011 = 3
100 = -0
101 = -1
110 = -2
111 = -3
由於符號占用一位,因此我只有兩位來編碼0到3的值。如果我加1到3,我將溢出-0作為結果。 是的,有兩個表示0,一個正面和一個負面。 您不會經常遇到符號幅度表示。
一個補碼:負值是正值的按位反轉。 再次,使用三位類型:
000 = 0
001 = 1
010 = 2
011 = 3
100 = -3
101 = -2
110 = -1
111 = -0
我有三位來編碼我的值,但范圍是[-3,3]。 如果我加1到3,我將溢出-3作為結果。 這與上面的符號幅度結果不同。 同樣,使用此方法有兩種編碼為0。
二進制補碼:負值是正值的逐位反轉加1.在三位系統中:
000 = 0
001 = 1
010 = 2
011 = 3
100 = -4
101 = -3
110 = -2
111 = -1
如果我加1到3,那么我將溢出-4,這與前兩種方法不同。 請注意,我們有一個稍大的值范圍[-4,3],只有一個表示為0。
二進制補碼可能是表示有符號值的最常用方法,但它不是唯一的,因此C標准無法保證溢出有符號整數類型時會發生什么。 因此它保留了未定義的行為,因此編譯器不必處理解釋多個表示。
當有符號整數類型可以表示為符號和幅度,一個補碼或二進制補碼時, 未定義的行為來自早期的可移植性問題。
如今,所有架構都將整數表示為兩個補碼。 但要小心:因為您的編譯器認為您不會運行未定義的行為是正確的,所以在啟用優化時可能會遇到奇怪的錯誤。
在帶符號的8位整數中,環繞的直觀定義可能看起來像是從+127到-128 - 在二進制補碼二進制中:0111111(127)和1000000(-128)。 如您所見,這是遞增二進制數據的自然進展 - 不考慮它表示整數,有符號或無符號。 直觀地說,當在無符號整數的環繞感中從-1(11111111)移動到0(00000000)時發生實際溢出。
這並沒有回答更深層次的問題,即當有符號整數溢出時正確的行為是什么,因為根據標准沒有“正確”的行為。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.