2015-02-08 42 views
0

我在編寫一個程序時遇到了麻煩,該程序要求用戶輸入一個值N,然後輸出結果5^N。問題是,如果用戶輸入了一個大於(2^31)-1的數字,他們的數字就會溢出,程序會給他們一個錯誤的答案。何時限制整數寬度?

我所做的是將用戶給定的整數值賦給一個無符號的長整數值。這樣,如果程序可以檢查是否輸入了大於(2^31)-1的數字,因爲無符號long可以保存比signed int更多的正整數。這樣做會導致程序正常工作,因爲我可以檢查是否發生溢出。

但是我的問題是這樣的:當用戶輸入一個大於2^31-1的值到原始的帶符號整數變量(這會導致它溢出)時,爲什麼我可以將這個溢出值賦值一個無符號的並得到什麼「正確」的號碼是?嘗試對該號碼進行操作時是否發生溢出?內存是否存儲實際數量(不受位寬限制)?

int endCount; 
unsigned long endCountUn; /* power N */ 

/* Read value of N */ 
printf("This program will compute 5^N; enter N: "); 
scanf("%d", &endCount); 

/* 
User's value put into unsigned long. Helps with detecting overflow. 
*/ 
endCountUn = endCount; 

if ((endCount < 0) && (endCountUn < 2147483648)) 
{ 
    printf("The operation is undefined for negative integers\n"); 
} 

else if (endCountUn > 2147483647) 
{ 
    printf("The value exceeds the supported numerical range\n"); 
} 
+0

在C,整數不會 「溢出」。您可以將其視爲模操作,其中某些操作的結果總是以「模2 ^(位)」進行處理。就像你寫的表達式附加了一個看不見的部分。簽名整數通常以2的補碼錶示。你的測試在你的第一個基本測試,如果上面 - 你的數字的符號位是1(這意味着否定的,如果它被解釋爲一個有符號的值)。所以你所需要了解的是查看2的補碼是如何工作的。 – BitTickler 2015-02-08 05:35:34

+0

@ user2225104:無符號整數不會溢出;它們將模2^N包裹,其中N是位數。另一方面,當有符號整數溢出時,會觸發未定義的行爲,並且可能發生任何事情(包括代碼似乎通過從正向轉爲負向工作)。未定義的行爲是未定義的。 – 2015-02-08 07:30:01

+0

請注意,當scanf()被要求處理的數字太大而不適合整數類型時,scanf()的行爲是不確定的。如果在32位有符號類型中輸入大於2^31-1的值,則得到的結果未定義。通常會發生什麼,但從形式上講,行爲是不確定的。 (ISO 9899:2011§7.21.6.2'fscanf'函數¶10表示_'...或者如果對象中的轉換結果不能表示爲 ,則行爲是未定義的。'_ – 2015-02-08 07:32:14

回答

1
if ((endCount < 0) && (endCountUn < 2147483648)) 

如果數n滿足這兩個條件時,執行此塊。 endCount,是一個(32位)有符號整數,用2的補碼錶示。 表達式的第一項由此選擇所有n,其中上部比特被設置:
範圍1:[0x80000000的...爲0xFFFFFFFF]
第二項選擇所有n分別在範圍
範圍2:[00000000 ..爲0x7FFFFFFF。
這兩個範圍內的n組是空集。 所以,如果你的上面的主體永遠不會被執行。

第二個if(否則,如果一部分)範圍請求值1.

所以,你的測試代碼可以簡化爲:

if(endCount < 0) { printf("Value out of range"); } 

因爲,無論用戶輸入什麼(一負值或範圍1中的值),endCount將始終爲負數。

最後,如果您只想允許無符號整數值,爲什麼您首先使用scanf("%d",endCount)
你可以代替寫:

uint32_t endCount = 0; // unsigned int is machine dependent...better use stdint.h... 
... 
scanf("%u", &endCount); 

輸出,用於這將被用來產生第二個printf聲明...

This program will compute 5^N; enter N: 2147483648 
The value exceeds the supported numerical range 

輸出,用於這將被用來產生第一個printf聲明...

This program will compute 5^N; enter N: -10 
The value exceeds the supported numerical range 

請看看你的系統這個對這個方案的產出...

uint32_t endCount; 

/* Read value of N */ 
printf("This program will compute 5^N; enter N: "); 
scanf("%u", &endCount); 

printf("entered value = %d (as signed)\n",endCount); 
printf("entered value = %u (as unsigned)\n",endCount); 

在我的系統:

This program will compute 5^N; enter N: -10 
entered value = -10 (as signed) 
entered value = 4294967286 (as unsigned) 
+0

感謝您的回答。我不想只允許無符號整數,因爲那樣我就無法檢查用戶是否輸入了一個負整數(除非我錯了)。我在這個程序中遇到的全部問題是,我無法確定用戶是否輸入了大於2^31-1的數字,因爲它翻轉爲負整數。如果我沒有這個支票,那麼當他們真的把一個非常大的正整數放入時,程序總是會認爲他們輸入了一個負整數。另外,要小心,endCount和endCountUn不是同一個變量。 – LTClipp 2015-02-08 15:34:00

+0

另外奇怪的是,這個程序完全按照它應該運行(至少在我的編譯器中)。任何時候你輸入一個負整數或者一個大於2^31-1的整數,就會執行正確的if語句。 – LTClipp 2015-02-08 15:43:14

+0

現在我好奇你在使用哪個系統和哪個編譯器:) – BitTickler 2015-02-08 17:55:30