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

Is this an unavoidable signed and unsigned integer comparison?

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

最近我在一个项目中将很多int转换为unsigned int。基本上所有不应该为负的东西都是无符号的。这删除了 ​​MinGW 的许多警告:

warning: comparison between signed and unsigned integer expressions [-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 发行版编译。

代替当前

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) 技术上是多余的,但为了保持一致性,因为第二个转换删除了 signed/unsigned 警告大概是这里的问题。

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

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


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

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

你犯了一个大错。

基本上你喜欢这个名字 "unsigned" 并且你希望它的意思是 "not negative" 但这不是与类型关联的语义。

考虑以下语句:

adding a signed integer and an unsigned integer the result is unsigned

显然,如果您将术语 "unsigned" 视为 "not negative" 是没有意义的,但这就是该语言的作用:将 -3 加到无符号值 2 上,您将得到一个巨大的无意义数字而不是正确答案 -1.

确实,选择使用无符号类型作为容器大小是 C++ 的设计错误,由于向后兼容性,现在修复这个错误为时已晚。顺便说一下,它发生的原因与 "non-negativeness" 无关,而只是与计算机那么小时使用第 16 位的能力有关(即能够使用 65535 个元素而不是 32767 个)。即使在那时,我也不认为错误语义的代价是值得的(如果 32767 现在还不够,那么 65535 很快就不够了)。

不要在您的程序中重复同样的错误...名称无关紧要,重要的是语义,对于 C 和 C++ 中的 unsigned,它是 "member of the Zn modulo ring with n=2k "。

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

首先,在不知道将存储在变量中的值的范围的情况下,您声称将有符号变量更改为无符号变量的说法没有根据 - 在某些情况下该说法是错误的。

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

一个经验法则是,如果您需要包含有符号和无符号类型的表达式,最好让所有相关变量都带符号。虽然也有不需要该经验法则的例外情况,但如果您了解如何做出决定,就不会问这个问题。

在此基础上,我建议最合适的操作是取消您的更改。