簡體   English   中英

在C中包含有符號和無符號變量的解釋?

[英]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.

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