2014-03-31 41 views
6

目前,我正在學習C程序,但我碰到一些奇怪的行爲 來到我的預期結果之一,但兩個結果印像這樣(i + 1)<ii和(i + 1)> ii都是如此嗎?

$ ./a.out 
yes1 0x80000000 
yes3 0x80000000 

怎麼會可能?
我無法理解結果。

OS : x86_64 Ubuntu Linux 
C compiler : gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 

gcc -O2 weird.c 

#include <stdio.h> 

int main() { 

    int i = 0x7fffffff; 
    int ii = 0x0000000f; 

    if ((i + 1) < ii) 
     printf ("yes1 %#x\n", i + 1); 

    if ((i + 1) == ii) 
     printf ("yes2 %#x\n", i + 1); 

    if ((i + 1) > ii) 
     printf ("yes3 %#x\n", i + 1); 

    return 0; 
} 
+1

爲0x7FFFFFFF + 1 = 爲0x80000000 –

+0

GCC(Ubuntu的/ Linaro的4.7.2-2ubuntu1)4.7 .2正確(在32位系統上) – fritzone

+0

它已被刪除,但您最初擁有C++標記,您是否關心C++? –

回答

7

在你的情況(我+ 1)滿溢過的範圍整型變量。

事實是,在一個有符號的int變量溢出是ANSI標準中的一個未定義的行爲,所以嚴格地說,它可能會導致任何結果。您的編譯器可能符合標準,但任何具有良好計算機理解的人都會期望該變量會溢出到負值,這僅僅是因爲計算機寄存器沒有明顯的有符號/無符號範圍。

以下是ANSI標準說上Undefined behavior(其它病例中):

在下列情況下的行爲是不明確:

算術運算是無效的(如除以0或模) 或產生的結果不能在提供的空間 (例如溢出或下溢)($ 3.3)中表示。

在另一側,這是無效的無符號類型:

涉及無符號的操作數的一種計算可以 永遠不會溢出,因爲這不能由 所得無符號整數類型是所表示的結果減少的模數爲 ,大於可由 產生的無符號整數類型表示的最大值。

同樣在這裏是相關部分從稱爲部分($ 3.3表達式):如果一個表達式的評估期間發生異常(即 ,如果結果不是數學上定義的或不

可表示), 行爲未定義。

+0

可以設置'-fwrapv',它使溢出完全定義爲環繞。 – Hasturkun

+0

推測'-fwrapv'會禁用我的答案中提到的問題優化。 – keshlam

+0

看起來你是在引用不是規範的附件,雖然我沒有發現C99草案或C11草案中的措辭是你引用C89的嗎? ANSI含糊不清,今天我會把它說成C11。 –

3

在你的代碼i+1所有的案件是生產符號整數溢出這是undefined behavior,這意味着程序行爲異常。我們可以看到它從draft C99 standard部分未定義6.5表達式款它說(重點煤礦):

如果表達式的計算(即過程中出現異常情況,如果 結果未在數學上定義爲或不在 類型的可表示值範圍內),因此行爲未定義

這也是草案C11標準中的同一部分。

一種可能的方式有感染,這將是使用紅clangs -fsanitize=undefined選項,這是部分clangs santizer suite我們得到以下運行時錯誤:

runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int' 
runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int' 
runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int' 
runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int' 
2

我認爲你正在運行到編譯器在哪裏是說,對於整數,x+1>y可以更有效地計算爲x>=y ...和優化的情況下不幸,而這是一般真實的,是永遠對無符號值,這個x + 1環繞爲負的特定情況打破了假設。

但是,由於帶符號的int溢出使我們進入未定義行爲的領域(請參閱@ Marian的回答),這並不正確。只是令人驚訝。

(約以爲刪除我的答案,但因爲它說明了如何測試都可能是真的,我認爲這是值得保留。)

+0

這不是一個編譯器錯誤。有符號的整數溢出是未定義的行爲。 – Hasturkun

+0

謝謝;適當澄清。 – keshlam

+0

這裏玩的具體優化是'-fstrict-overflow'。在'-O2'下,gcc啓用'-fstrict-overflow'優化,這使得它可以假定簽名溢出是未定義的。使用'-fwrapv'會使編譯器認爲溢出會導致環繞。除此之外,在C99規範3.4.3章節中,給出了未定義行爲定義的例子:「未定義行爲的一個例子是整數溢出的行爲」 – Hasturkun

相關問題