给出以下(伪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;)?使用演员表是否有任何开销(我需要快速工作!)?
编辑:我将所有未签名的注册内容更改为常规注册,但我仍然想知道为什么在这种情况下会出现溢出。
答案 0 :(得分:7)
无符号整数实现无符号算术。无符号算术是模数算术。所有值都以2 ^ N为模调整,其中N是无符号类型值表示中的位数。
简单来说,无符号算术总是产生非负值。每次表达式应该导致负值时,该值实际上“包围”2 ^ N并变为正值。
在[sub-]表达式中混合有符号和无符号整数时,无符号算术“获胜”,即计算在无符号域中执行。例如,当您执行col - hw
时,它将被解释为(unsigned) col - hw
。这意味着对于col == 0
和hs == 31
,您不会得到-31
作为结果。相反,你会得到UINT_MAX - 31 + 1
,这通常是一个巨大的正值。
话虽如此,我必须指出,在我看来,使用无符号类型来表示固有的非负值总是一个好主意。实际上,在实践中,C / C ++中的大多数(或至少一半)整数变量应该具有无符号类型。您在示例中尝试使用无符号类型是合理的(如果正确理解了意图)。此外,我还将unsigned
用于col
和row
。但是,您必须记住无符号算术的工作方式(如上所述)并相应地编写表达式。大多数情况下,可以重写表达式,使其不超过无符号范围的界限,即大多数情况下不需要显式地将任何内容转换为有符号的类型。否则,如果您确实需要最终使用负值,那么对签名类型进行良好放置的转换应该可以解决问题。
答案 1 :(得分:2)
如何制作height
,width
和hw
签名的内容?通过让他们不签名你真正获得了什么?混合有符号和无符号整数总是在寻找麻烦。乍一看,至少看起来你在这里使用无符号值看起来并没有获得任何东西。所以,你不妨让它们全部签名并为你省去麻烦。
答案 2 :(得分:1)
您有向后转换规则 - 当您混合相同类型的有符号和无符号版本时,已签名的操作数将转换为无符号。
答案 3 :(得分:0)
如果你想要快速,你应该在开始循环之前static_cast所有无符号值并使用它们的int版本而不是unsigned int。您仍然可以要求输入是无符号的,然后将它们转换为您的算法,以保留您的函数所需的域。
答案 4 :(得分:0)
强制转换不会自动发生 - 未经验证的算术仍然有它的用途。通常的例子是int / int = int,即使数据因未转换为float而丢失。我会使用signed int,除非因为INT_MAX太小而无法这样做。