深入理解計算機系統 練習題2.25-隱式強制類型轉換導致的數組越界
1 #include <stdio.h> 2 #include <iostream> 3 using namespace std; 4 5 float sum_elements(float a[], unsigned length) { 6 int i; 7 float result = 0; 8 cout << length << endl; 9 cout << length - 1 << endl; 10 for (i = 0; i <= length - 1;i++) { 11 result += a[i]; 12 } 13 return result; 14 } 15 16 int main() 17 { 18 unsigned length =5; 19 float a[length]={1.0,2.0,3.0,4.0,5.0}; 20 float sum; 21 sum=sum_elements(a, 1); 22 printf("%0.1f",sum); 23 }
問:
當函數參數length為0時,運行這段代碼應該返回0.0。但實際上,運行時會遇到一個存儲器錯誤。請問為什麽會發生這種情況,並且說明如何修改代碼?
結果如下:
length為正數時,結果正確。並且length-1的結果也正確。
但是當length為0的時候,length-1變成了4294967295;
0
4294967295
Process returned -1073741819 (0xC0000005) execution time : 2.188 s
Press any key to continue.
分析:
因為length是一個無符號數,1是有符號數,所以C語言會把length-1轉換為無符號計算;
當length為0時,length-1的結果為-1,既然是無符號計算,就不可能有負數的結果,
所以無符號數是如何解釋-1的呢?對於無符號計算它是無法理解負數結果的。
-1的補碼為0xFFFFFFFF,這個位模式會被解釋成無符號數的值,即:4294967295;
所以計算結果為4294967295,造成了數組越界,出現錯誤。
那麽對於length是正數,為什麽沒有問題?->我的理解是計算還是被轉換為無符號計算,
只是用無符號計算的方式解釋結果與有符號計算的方式解釋結果正好相同,所以沒有問題暴露。
為了避免該問題,該如何修改代碼呢?
很簡單,加個if語句,排除length等於0的情況即可。
規則:
C語言對於同時包含有符號數和無符號數表達式出現了奇特的處理行為,C語言會隱式地將有符號參數強制類型轉換成無符號數,並假設這兩個數都是非負的,來執行這個計算。
C語言允許無符號數和有符號數之間的轉換。記住轉換的原則是底層的位表示保持不變。
當無符號數轉換為有符號數時,效果就是運用U2T函數;
當有符號數轉換為無符號數時,效果就是運用T2U函數;
深入理解計算機系統 練習題2.25-隱式強制類型轉換導致的數組越界