首页 文章

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

提问于
浏览
13

我被建议在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 回答

  • 0

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

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

  • 0

    无论铸造贬值困境如何,我仍然建议将逻辑从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循环声明应该是干净的,并且不应产生任何错误 . 你的演员阵容发生在不同的位置,这意味着如果你想改变你创建范围的方式,你就不必再做更长时间的声明了 .

  • 14

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

  • 0

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

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

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

  • 0

    更换

    int x;
    /* ... */
    for(x=0;x<sizeof(arr) / sizeof(int);x++)
    

    通过

    for(size_t x=0;x<sizeof(arr) / sizeof(int);x++)
    

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

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

  • 4

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

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

    无论是严格选择你的类型的signedeness,还是在你申请时摆脱麻烦,或者摆脱 -Werror 并制定一个政策来解决所有警告带有修复或解释......

  • 2

    一种解决方法是在这种特殊情况下有选择地禁用该警告 . GCC has pragma diagnostic ignored "-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”来抑制警告 .

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

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

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

    编辑:

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

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

相关问题