簡體   English   中英

無符號算術和整數溢出

[英]Unsigned arithmetic and integer overflow

我試圖了解算術溢出。 假設我有以下內容,

unsigned long long x;
unsigned int y, z;

x = y*z;

y * z可能導致整數溢出。 是否將操作數之一轉換為unsigned long long可以緩解此問題。 64位操作數與32位操作數相乘的預期結果是什么?

您清楚地假設unsigned int是32位, unsigned long long 64位。 他們不必如此,讓我們來假設這一點。

通過轉換32位操作數獲得的64位操作數仍然適合32位。 因此,在y*(unsigned long long)z ,每個操作數首先被提升為unsigned long long ,結果被計算為unsigned long long ,並且不能“溢出”,因為這是兩個量化的乘積每個32位。

(此外,在C標准的詞匯中,未簽名的操作不會“溢出”。溢出是在目標類型的邊界之外產生結果的未定義行為。未簽名的操作所進行的是“環繞”)。

unsigned long long x;
unsigned int y, z;

x = y*z;

表達式y*z的求y*z不受它出現的上下文的影響。 它將兩個unsigned int值相乘,得出unsigned int結果。 如果數學結果不能表示為unsigned int值,則結果將環繞。 然后,賦值將(可能被截斷的)結果從unsigned int隱式轉換為unsigned long long

如果要使乘法產生unsigned long long結果,則需要顯式轉換一個或兩個操作數:

x = (unsigned long long)y * z;

或者,更明確地說:

x = (unsigned long long)y * (unsigned long long)z;

C'S *乘法運算符適用於同一類型的兩個操作數。 因此,當您為它提供不同類型的操作數時,在執行乘法運算之前,它們將轉換為某種常見類型。 當您混合帶符號和無符號類型時,規則可能會有點復雜,但是在這種情況下,如果將unsigned long longunsigned int相乘, unsigned long long unsigned int操作數將被提升為unsigned long long

如果 unsigned long long寬度至少是大多數系統上unsigned int兩倍,那么結果將不會溢出也不會回繞,因為例如64位unsigned long long可以保存乘以任意值的結果兩個32位unsigned int值。 但是,如果您使用的系統(例如intlong long均為64位寬),您仍然可以進行 溢出 回繞,使x的結果不等於yz的數學乘積。

如果一個操作數的寬度大於另一個操作數的寬度,則編譯器應將兩個操作數轉換為相同的大小,或者將其轉換為相同的大小,因此將一個操作數轉換為較大的大小將產生正確的行為。

這是在C和C ++標准中指定的。 C ++ 11標准(n3337草案)在第五章中聲明9:

...如果兩個操作數都具有符號整數類型或都具有無符號整數類型,則整數轉換等級較小的操作數應轉換為等級較高的操作數的類型。

有幾頁描述了所有的轉換和正在進行的事情,但這正是定義此特定表達式的行為的原因。

暫無
暫無

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

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