[英]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 long
與unsigned int
相乘, unsigned long long
unsigned int
操作數將被提升為unsigned long long
。
如果 unsigned long long
寬度至少是大多數系統上unsigned int
兩倍,那么結果將不會溢出也不會回繞,因為例如64位unsigned long long
可以保存乘以任意值的結果兩個32位unsigned int
值。 但是,如果您使用的系統(例如int
和long long
均為64位寬),您仍然可以進行
溢出
回繞,使x
的結果不等於y
和z
的數學乘積。
如果一個操作數的寬度大於另一個操作數的寬度,則編譯器應將兩個操作數轉換為相同的大小,或者將其轉換為相同的大小,因此將一個操作數轉換為較大的大小將產生正確的行為。
這是在C和C ++標准中指定的。 C ++ 11標准(n3337草案)在第五章中聲明9:
...如果兩個操作數都具有符號整數類型或都具有無符號整數類型,則整數轉換等級較小的操作數應轉換為等級較高的操作數的類型。
有幾頁描述了所有的轉換和正在進行的事情,但這正是定義此特定表達式的行為的原因。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.