深入理解计算机系统 练习题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函数;

原文地址:https://www.cnblogs.com/grooovvve/p/10323953.html