比较unsigned和signed int

时间:2016-11-11 17:15:54

标签: c casting

我想这是经典问题之一。

据我所知,比较unsignedsigned 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;
}

6 个答案:

答案 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 == 0length - 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;
}