我被建议在GCC中使用以下选项,因为它有助于避免许多常见错误 . 它会打开一堆警告,并将它们变成错误 .
gcc -pedantic -W -Wall -Wextra -Wshadow -Wstrict-overflow=5 -Wwrite-strings -std=c99 -Werror
鉴于以下测试代码:
#include <stdio.h>
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;
但是,当我必须使用这些编译器选项将带符号值与无符号值进行比较时,它无法解决一般问题 . 是否有更清洁的方式而不是铸造?
8 回答
我们在Visual Studio编译中禁止此警告,因为它发生了很多,几乎从未意味着任何重要的事情 . 当然,并非所有编码标准都允许这样做 .
您可以使类型一致(例如,将变量声明为size_t或unsigned int而不是int),或者可以强制转换,或者可以更改编译行 . 就是这样 .
无论铸造贬值困境如何,我仍然建议将逻辑从for循环中分离出来 .
虽然这使用了您所说的已弃用的铸件,但它会清除铸件发生的位置 . 一般来说,我建议不要在你的for循环声明中塞入很多逻辑 . 特别是在你使用size_t除法的情况下(因为它是整数除法)可能会截断答案 . for循环声明应该是干净的,并且不应产生任何错误 . 你的演员阵容发生在不同的位置,这意味着如果你想改变你创建范围的方式,你就不必再做更长时间的声明了 .
一个选项是附加标志“-Wno-sign-compare”:)
这实际上取决于数据类型 . 可以通过将值隐式转换为包含signed和unsigned类型中所有可用值的超集的类型来避免这种情况 . 例如,您可以使用64位有符号值来比较无符号32位和带符号32位值 .
但是,这是一个极端情况,您需要执行操作,例如验证类型的大小 . 您最好的解决方案是对两个操作数使用相同的类型 .
如果你必须施放,请考虑你可能导致溢出,并考虑这是否对你的应用程序很重要 .
更换
通过
在这种情况下,请尝试确定带符号的数字是否会有一个会导致溢出的值 . 如果没有,您可以忽略该警告 . 否则,对无符号类型的强制转换(如果它与签名组件大小相同或更大)就足够了 .
问题的关键在于比较有符号和无符号值会引发一些奇怪的情况 . 例如,考虑无符号数组长度中发生的事情大于signed int表示的最大值 . 签名计数器溢出(剩余“小于”数组大小),并开始寻址内存,你不是故意...
编译器会生成警告以确保您正在考虑它们 . 使用
-Werror
将该警告提升为错误并停止编译 .无论是严格选择你的类型的signedeness,还是在你申请时摆脱麻烦,或者摆脱
-Werror
并制定一个政策来解决所有警告带有修复或解释......一种解决方法是在这种特殊情况下有选择地禁用该警告 . GCC has pragma diagnostic ignored "-Wsomething"
GCC的最新版本(我实际上不确定,但是4.8.x应该支持它)显示相应的-Wsomething选项 . 这一点非常重要,因为大多数警告选项都没有明确设置,而是与-Wall等选项一起使用 . 错误消息如下所示:
[-Werror = sign-compare]部分告诉您可以使用“Wsign-compare”作为“Wsomething”来抑制警告 .
当然,你应该只在合适的地方做这件事(它的可读性不大),例如:何时需要编译器警告的行为(或者,如果您可能不在代码库中引入更大的更改) .
您可以将x声明为unsigned int,因为size_t是无符号的
编辑:
如果你不想演员,并且不想将其声明为无符号,我认为没有太多事要做 .
也许按位运算是一种解决方法,删除符号位 . 我不得不说,IMO非常值得怀疑 .