我想这是经典问题之一。
据我所知,比较unsigned
和signed
int是使用无符号算术执行的,这意味着如果length = -1 = unsigned max of 32 bits
。
可以通过将长度声明为int来修改代码,或者通过将for循环的测试更改为i<长度。
将长度声明为int,它很容易理解,但更改loop to be i < length
并不容易。
如果我们遇到以下情况:5 < -1
如果使用无符号算术执行,在我的计算机中产生5 < 4294967295
,这怎么可能是一个解决方案,它似乎会访问未定义的元素。
代码
float sum_elements(float a[], unsigned length)
{
int i;
float result = 0;
for (i = 0; i <= length-1; i++)
result += a[i];
return result;
}
答案 0 :(得分:1)
考虑条件。
i&lt; = length-1
正如你所提到的,如果长度为零,那么你将进入像5&lt; 4294967295。
将条件更改为“i&lt; length”将阻止此情况。
同样将变量“i”的类型更改为“unsigned”是有意义的,因为(a)它是数组索引。 (b)您将其与“未签名”进行比较。
所以我更喜欢这段代码。
float sum_elements(float a[], unsigned length)
{
unsigned i = 0;
//float result = 0.0; //Refer comment section.
double result = 0.0;
for (i = 0; i < length; i++)
result += (double)a[i];
return result;
}
答案 1 :(得分:0)
与<=
的迂腐int <= unsigned
比较首先会测试负面因素。
for (i = 0; i < 0 || ((unsigned) i) <= length-1; i++)
删除-1有助于避免溢出。
for (i = 0; i < 0 || ((unsigned) i) < length; i++)
一个好的编译器可能会优化代码,因此2比较实际上不在可执行文件中。
如果未使用-Wsign-conversion
或其等效的编译器选项,请删除强制转换代码@R..
for (i = 0; i < 0 || i < length; i++)
同样由@chqrlie评论,比较可能表现良好,但i
上的后续操作可能会出现问题。特别是在i == INT_MAX
时,i++
是UB。
最好使用size_t
(无符号类型)进行数组大小计算和索引。
float sum_elements(float a[], size_t length) {
float result = 0;
size_t i;
for (i = 0; i < length; i++)
result += a[i];
return result;
}
答案 2 :(得分:0)
选项#1:
for (i = 0; i <= (int)length-1; i++)
选项#2:
for (i = 0; i+1 <= length; i++)
选项#3:
for (i = 0; i < length; i++)
答案 3 :(得分:0)
这是你的编译器工作,当他创建解析器词法分析器时,他使用表来表示你的变量。如果他看到类似的东西:
float a = b + 60
60将由您的编译器以60.0投射 我认为这是同样的事情:
(unsigned int)length = (unsigned int)length (int)-1
变为:
(unsigned int)length = (int)length (int)-1;
如果要进行正确的算术比较,则应使用标志-Wextra
答案 4 :(得分:0)
在以下两种情况下,您的代码将无法按预期执行:
如果使用无符号算术计算的length == 0
,length - 1
是一个非常大的数字,并且比较i <= length - 1
将始终为真,因为比较也是使用无符号算术执行的。
如果length
大于最大整数值,i
永远不会达到这样的值,虽然使用无符号算术执行的比较将按预期工作,但索引{{1}在负索引指向数组外的64位系统上将会出现错误。
编译器正确诊断出一个真正的问题。对a[i]
使用签名类型并将其与无符号i
表达式进行比较可能会导致意外行为。以这种方式解决问题:
length
注意:
float sum_elements(float a[], unsigned length) {
double result = 0.0;
for (unsigned i = 0; i < length; i++) {
result += a[i];
}
return result;
}
和length
的类型确实应该是i
,因为这可能比size_t
更大。
总和应使用unsigned
算术计算,以获得比使用double
更高的精度。精度会更好,但仍然有限。以不同的顺序对数组元素求和可以产生不同的结果。
答案 5 :(得分:0)
丢失i
变量,以节省一点堆栈空间并使功能更快。
float sum_elements(float a[], unsigned length)
{
float result = 0;
while (length--)
result += *a++;
return result;
}