为什么在使用C ++的表达式中使用无符号整数时会出错?

时间:2010-05-17 17:04:20

标签: c++ expression unsigned

给出以下(伪C ++)代码:

float x=100, a=0.1;
unsigned int height = 63, width = 63;
unsigned int hw=31;
for (int row=0; row < height; ++row)
{
    for (int col=0; col < width; ++col)
    {
        float foo = x + col - hw + a * (col - hw);
        cout << foo << " ";
    }
    cout << endl;
}

在(col - hw)为负的地方,foo的值被拧紧了一半的数组。我想因为col是int而且是第一个,表达式的这一部分转换为int并变为负数。不幸的是,显然它没有,我得到一个无符号值的溢出,我不知道为什么。

我该如何解决这个问题?使用强制转换表达整个或部分表达式?什么类型的演员表(C风格或static_cast&lt; ...&gt;)?使用演员表是否有任何开销(我需要快速工作!)?

编辑:我将所有未签名的注册内容更改为常规注册,但我仍然想知道为什么在这种情况下会出现溢出。

5 个答案:

答案 0 :(得分:7)

无符号整数实现无符号算术。无符号算术是模数算术。所有值都以2 ^ N为模调整,其中N是无符号类型值表示中的位数。

简单来说,无符号算术总是产生非负值。每次表达式应该导致负值时,该值实际上“包围”2 ^ N并变为正值。

在[sub-]表达式中混合有符号和无符号整数时,无符号算术“获胜”,即计算在无符号域中执行。例如,当您执行col - hw时,它将被解释为(unsigned) col - hw。这意味着对于col == 0hs == 31,您不会得到-31作为结果。相反,你会得到UINT_MAX - 31 + 1,这通常是一个巨大的正值。

话虽如此,我必须指出,在我看来,使用无符号类型来表示固有的非负值总是一个好主意。实际上,在实践中,C / C ++中的大多数(或至少一半)整数变量应该具有无符号类型。您在示例中尝试使用无符号类型是合理的(如果正确理解了意图)。此外,我还将unsigned用于colrow。但是,您必须记住无符号算术的工作方式(如上所述)并相应地编写表达式。大多数情况下,可以重写表达式,使其不超过无符号范围的界限,即大多数情况下不需要显式地将任何内容转换为有符号的类型。否则,如果您确实需要最终使用负值,那么对签名类型进行良好放置的转换应该可以解决问题。

答案 1 :(得分:2)

如何制作heightwidthhw签名的内容?通过让他们不签名你真正获得了什么?混合有符号和无符号整数总是在寻找麻烦。乍一看,至少看起来你在这里使用无符号值看起来并没有获得任何东西。所以,你不妨让它们全部签名并为你省去麻烦。

答案 2 :(得分:1)

您有向后转换规则 - 当您混合相同类型的有符号和无符号版本时,已签名的操作数将转换为无符号。

答案 3 :(得分:0)

如果你想要快速,你应该在开始循环之前static_cast所有无符号值并使用它们的int版本而不是unsigned int。您仍然可以要求输入是无符号的,然后将它们转换为您的算法,以保留您的函数所需的域。

答案 4 :(得分:0)

强制转换不会自动发生 - 未经验证的算术仍然有它的用途。通常的例子是int / int = int,即使数据因未转换为float而丢失。我会使用signed int,除非因为INT_MAX太小而无法这样做。