如何修复警告:“签名和未签名之间的比较”?

我被建议在GCC中使用以下选项,因为它有助于避免许多常见错误。 它打开了一堆警告,并且-Werror将它们变成了错误。

 gcc -pedantic -W -Wall -Wextra -Wshadow -Wstrict-overflow=5 -Wwrite-strings -std=c99 -Werror 

鉴于以下测试代码:

 #include  int main(void) { int arr[8]={0,10,20,30,40,50,60,70}; int x; printf("sizeof(arr): %d\n", sizeof(arr)); printf("sizeof(int): %d\n", sizeof(int)); for(x = 0; x < sizeof(arr)/sizeof(int); x++) { printf("%d\n",arr[x]); } return 0; } 

我明白了:

 test.c:11: error: comparison between signed and unsigned 

我知道我可以解决这个问题的一种方法就是关闭警告,但是他们还没有让我使用这些设置来最终关闭它们。

另一种方法是投射东西,但我被告知铸造已被弃用。

另外,我可以将x变成unsigned int

 unsigned x; 

但是,当我必须使用这些编译器选项将带符号值与无符号值进行比较时,它无法解决一般问题。 是否有更清洁的方式而不是铸造?

这实际上取决于数据类型。 可以通过将值隐式转换为包含signed和unsigned类型中所有可用值的超集的类型来避免这种情况。 例如,您可以使用64位有符号值来比较无符号32位和带符号32位值。

但是,这是一个极端情况,您需要执行操作,例如validation类型的大小。 您最好的解决方案是对两个操作数使用相同的类型。

如果你必须施放,请考虑你可能导致溢出,并考虑这是否对你的应用程序很重要。

更换

 int x; /* ... */ for(x=0;x 

通过

 for(size_t x=0;x 

但是,当我必须使用这些编译器选项将带符号值与无符号值进行比较时,它无法解决一般问题。 是否有更清洁的铸造方式?

在这种情况下,尝试确定带符号的数字是否可能具有会导致溢出的值。 如果没有,您可以忽略该警告。 否则,对无符号类型的强制转换(如果它与签名组件大小相同或更大)就足够了。

问题的关键在于比较有符号和无符号值会引发一些奇怪的情况。 例如,考虑无符号数组长度中发生的情况大于signed int表示的最大值。 签名的计数器溢出(剩余“小于”数组大小),并开始寻址你并不意味着…

编译器会生成警告以确保您正在考虑它们。 使用-Werror将该警告提升为错误并停止编译。

无论是严格选择你的类型的signedeness,还是在你确定它不适用时抛弃麻烦,或者摆脱-Werror并制定政策来解决所有警告的修复或解释。 。

一种解决方法是在这种特殊情况下有选择地禁用该警告。 GCC的pragma诊断忽略了 “-Wsomething”

 // Disable a warning for a block of code: #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wmissing-prototypes" // ... Some code where the specified warning should be suppressed ... #pragma GCC diagnostic pop 

最新版本的GCC(我实际上并不确定,但是4.8.x应该支持它)显示相应的-Wsomething选项。 这一点非常重要,因为大多数警告选项都没有明确设置,而是与-Wall等选项一起使用。 错误消息如下所示:

 readers.c: In function 'buffered_fullread': readers.c:864:11: error: comparison between signed and unsigned integer expressions [-Werror=sign-compare] if(got < sizeof(readbuf)) /* That naturally catches got == 0, too. */ 

[-Werror = sign-compare]部分告诉您可以使用“Wsign-compare”作为“Wsomething”来抑制警告。

当然,你应该只在合适的地方做这件事(它没有太大帮助的可读性),例如,当需要编译器警告的行为时(或者,如果您可能不会在代码库中引入更大的更改)。

 test.c:11: error: comparison between signed and unsigned 

您可以将x声明为unsigned int,因为size_t是无符号的

编辑:

如果你不想演员,并且不想将其声明为无符号,我认为没有太多事要做。

也许按位运算是一种解决方法,删除符号位。 我不得不说,IMO非常值得怀疑。

我们在Visual Studio编译中禁止此警告,因为它发生了很多,几乎从未意味着任何重要的事情。 当然,并非所有编码标准都允许这样做。

您可以使类型一致(例如,将变量声明为size_t或unsigned int而不是int),或者可以强制转换,或者可以更改编译行。 就是这样。

无论铸造贬值困境如何,我仍然建议将逻辑从for循环中分离出来。

 int range = (int)(sizeof(arr) / sizeof(int)); int x; for(x = 0; x < range; x++) { printf("%d\n", arr[x]); } 

虽然这使用了您所说的已弃用的铸件,但它会清除铸件发生的位置。 一般来说,我建议不要在你的for循环声明中塞入很多逻辑。 特别是在你使用size_t除法的情况下,(因为它是整数除法)可能会截断答案。 for循环声明应该是干净的,并且不应产生任何错误。 你的演员阵容发生在不同的位置,这意味着如果你想改变你创建范围的方式,你就不必再为更长时间做出声明了。

一个选项是附加标志“-Wno-sign-compare”:)