这是不可避免的有符号和无符号整数比较吗?

时间:2015-06-12 09:18:09

标签: c++ casting unsigned signed

可能不是,但我不能想出一个好的解决方案。我还没有C ++专家。

最近,我在项目中将很多int转换为unsigned int s。基本上所有永远不应该是负面的东西都是无条件的。这消除了MinGW的许多警告:

  

警告:有符号和无符号整数表达式之间的比较[-Wsign-compare]

我喜欢它。它使程序更健壮,代码更具描述性。但是,有一个地方仍然存在。它看起来像这样:

unsigned int subroutine_point_size = settings->get<unsigned int>("subroutine_point_size");
...
for(int dx = -subroutine_point_size;dx <= subroutine_point_size;dx++) //Fill pixels in the point's radius.
{
    for(int dy = -subroutine_point_size;dy <= subroutine_point_size;dy++)
    {
        //Do something with dx and dy here.
    }
}

在这种情况下,我无法使dxdy无符号。它们开始是否定的,并且依赖于比较哪个更小或更大。

我也不想让subroutine_point_size签名,尽管这是较小的罪恶。它表示在图像上传递内核的大小,并且内核大小不能为负(对于用户将此内核大小设置为超过100但不是设置的用户来说,这可能是不明智的文件允许数字最多为2 ^ 32 - 1)。

所以似乎没有办法转换任何变量来解决这个问题。有没有办法摆脱这个警告并整齐地解决这个问题?

我们正在使用C ++ 11,使用GCC编译Windows,Mac和各种Unix发行版。

4 个答案:

答案 0 :(得分:2)

将变量转换为long intlong long int类型,同时给出unsigned int(0..2 ^ 32-1)和sign的范围。

答案 1 :(得分:1)

取代当前的

for(int dx = -subroutine_point_size;dx <= subroutine_point_size;dx++) //Fill pixels in the point's radius.

你可以这样做:

for(int dx = -int(subroutine_point_size);dx <= int(subroutine_point_size);dx++) //Fill pixels in the point's radius.

其中第一个int强制转换(1)在技术上是多余的,但是为了保持一致性,因为第二个强制转换会删除签名/未签名的警告,这可能是此处的问题。< / p>

但是,我强烈建议您撤消将签名转换为无符号类型的工作。一个好的经验法则是使用签名类型表示数字,使用无符号类型表示位级别的东西。这避免了由于隐式转换引起的环绕问题,例如,保证std:.string("Bah").length() < -5(非常愚蠢),并且因为它消除了实际问题,它还减少了虚假警告。

请注意,您只需定义一个合适的名称,您可以在其中指明某些值永远不会为负值。

1)技术上冗余在实践中,用于有符号整数的二进制补码表示,编译器不插入陷阱。据我所知,现有的C ++编译器没有其他行为。 功能

答案 2 :(得分:1)

你犯了一个大错误。

基本上你喜欢这个名字&#34; unsigned&#34;而你打算用它来表示&#34;而不是消极&#34;但这不是与该类型相关的语义。

考虑声明:

  

添加有符号整数和无符号整数,结果为无符号

显然,如果你考虑一下这个术语&#34; unsigned&#34;作为&#34;不是否定&#34;,但这就是语言的作用:向无符号值2添加-3将得到一个巨大的无意义数字而不是正确答案-1。

实际上,对容器大小使用无符号类型的选择是C ++的设计错误,由于向后兼容性,这个错误现在为时已晚。顺便说一下它发生的原因与非负面性#34;无关,但只是当计算机那么小时能够使用第16位(即能够使用65535个元素而不是32767) 。即使在那时我也不认为错误语义的价格值得获得(如果现在32767还不够,那么65535韩元也不会很快就足够了)。

不要在你的程序中重复同样的错误...这个名字是无关紧要的,重要的是语义,对于C和C ++中的unsigned,它是&#34; Z n的成员模数环,n = 2 k &#34;。

您不希望容器的大小成为模数环的成员。你呢?

答案 3 :(得分:0)

首先,在不知道将存储在变量中的值的范围的情况下,您声称将签名更改为无符号变量的说法未经证实 - 有些情况下该声明是错误的。

其次,编译器不会仅仅因为更改变量(我假设调用模板函数如settings.get())而无法发出警告。它警告你有表达涉及有符号和无符号变量的事实。编译器通常会发出有关此类表达式的警告,因为 - 实际上 - 它们更可能表示编程错误或可能涉及程序员可能没有预料到的某些行为(例如,未定义行为的实例,预期否定结果的表达式,但是大的积极结果是会发生什么等等。

根据经验,如果您需要包含有符号和无符号类型的表达式,最好将所有相关变量都签名。虽然不存在不需要经验法则的例外情况,但如果您了解如何做出决定,则不会问这个问题。

在此基础上,我建议最合适的行动是放松你的变化。