2014-10-04 53 views
4

我有下面的C代碼:當C表達式發生整數溢出時會發生什麼?

uint8_t firstValue = 111; 
uint8_t secondValue = 145; 
uint16_t temp = firstValue + secondValue; 
if (temp > 0xFF) { 
    return true; 
} 
return false; 

這是另一種實現:

uint8_t firstValue = 111; 
uint8_t secondValue = 145; 
if (firstValue + secondValue > 0xFF) { 
    return true; 
} 
return false; 

第一個例子是顯而易見的,uint16_t類型是大到足以容納結果。 當我在OS/X上使用clang編譯器嘗試第二個示例時,它正確地返回true。那裏會發生什麼?有沒有某種臨時,更大的類型來包含結果?

+0

對於無符號類型,結果是「它應該是」以接收變量的大小爲模。我的意思是:只有適合的位被存儲;剩下的(如果有的話)被忽略。對於簽名類型,結果是未定義的。 – wildplasser 2014-10-04 18:39:30

回答

7

+操作數被提升到更大的類型,我們可以通過將draft C99 standard部分6.5.6加法運算符它說看到這一點:

如果兩個操作數的算術類型,通常的算術轉換中進行在 他們。

,如果我們去6.3.1.8常見的算術轉換它說:

否則,整促銷活動是在兩個操作數執行。

,然後我們去6.3.1.1布爾,字符和整數它說(重點煤礦):

如果int可以表示原始類型的所有值,該值轉換爲int; 否則,它被轉換爲一個unsigned int。 這些被稱爲整數 促銷 .48)所有其他類型是由整數促銷不變。

所以+在這種情況下,兩個操作數將被提升爲鍵入INT的操作,所以沒有溢出。

注意,Why must a short be converted to an int before arithmetic operations in C and C++?解釋促銷的理由。

0

在C中,中間結果至少爲int,如果輸入類型較長或數據類型較大,則更寬。

3

第一個例子很明顯,uint16_t類型足夠大以包含結果。

事實上目的地左值x的分配x = expr;對是否有expr溢出沒有影響。如果有,那麼結果就是它是什麼,不管x有多寬。

在您的示例中,「整數升級」適用,計算在int操作數之間完成。這意味着沒有溢出。整數升級在C11第6.3.1.1節中描述。

如果您已經添加了兩個uint32_t值,那麼可能會出現環繞(無符號操作產生超出無符號類型範圍的結果時的指定行爲),即使左值類型分配結果爲uint64_t

+0

+1你和Jens從字面上回答我後,我實際上等着看有沒有人會用更好的答案跳進來,我原本打算只發表評論。 – 2014-10-04 18:46:27

2

是,全部算術運算的寬度至少爲int。因此,您的操作數首先轉換爲int,然後執行操作。就像在第一個例子中那樣,結果然後被轉換回分配的目標類型。

通常,使用窄類型進行算術不是一個好主意。儘可能避免這種情況,這隻會讓事情變得複雜。最好的辦法是完全避免這些類型,除非你真的有問題需要存儲大量的數字,例如

相關問題