如何处理来自GCC的-Wconversion警告?

5

我正在使用GCC的-Wconversion警告标志构建我的项目。(gcc(Debian 4.3.2-1.1)4.3.2)在64位GNU / Linux OS /硬件上。我发现它对于识别我混合类型或失去应该使用哪些类型的清晰度非常有用。

在大多数激活其警告的其他情况下,它并不是很有帮助,我想知道我应该如何处理这些情况:

enum { A = 45, B, C };   /* fine */

char a = A;              /* huh? seems to not warn about A being int. */
char b = a + 1;          /* warning converting from int to char */
char c = B - 2;          /* huh? ignores this *blatant* int too.*/
char d = (a > b ? b : c) /* warning converting from int to char */

由于上述测试的意外结果(情况ac),我也要求解释这些差异。
编辑:将所有这些内容都用(char)转换以防止警告,这是否过度设计?
编辑2:一些额外情况(接着上述情况):
a += A;         /* warning converting from int to char */
a++;            /* ok */
a += (char)1;   /* warning converting from int to char */

除此之外,我要问的是主观的,并且我想听听其他人在类似情况下如何处理转换警告,考虑到一些开发人员主张删除所有警告。
YAE:
一个可能的解决方案是只使用int而不是char,对吧?实际上,它不仅需要更多的内存,而且速度也更慢,正如以下代码所示。数学表达式只是为了在使用-Wconversion编译时获得警告。我假设使用char变量的版本会比使用int变量的版本运行得更慢,因为需要进行转换,但在我的(64位双核II)系统上,int版本更慢。
#include <stdio.h>

#ifdef USE_INT
typedef int var;
#else
typedef char var;
#endif

int main()
{
    var start = 10;
    var end = 100;
    var n = 5;
    int b = 100000000;
    while (b > 0) {
        n = (start - 5) + (n - (n % 3 ? 1 : 3));
        if (n >= end) {
            n -= (end + 7);
            n += start + 2;
        }
        b--;
    }
    return 0;
}

向gcc传递-DUSE_INT参数,以构建上述代码段的整数版本。


2
当您使用A > 255进行编译时,它会显示什么? - György Andrasek
1
使用 A = 256,对于 char a = A,会显示警告信息:“warning: overflow in implicit constant conversion”;对于 char c = B - 2,会显示警告信息:“warning: conversion to ‘char’ alters ‘int’ constant value”。 - James Morris
2个回答

2

当你说/* int */时,是指它给出了一个警告吗?我在使用 gcc 4.0.1 或带有 -Wconversion 的 4.2.1 版本的代码中没有看到任何警告。编译器正在将这些枚举转换为常量。由于所有信息在编译时都是已知的,因此没有理由生成警告。编译器可以优化掉所有的不确定性(以下是使用 Intel 编译器和 4.2.1 版本的情况):

    movb    $45, -1(%rbp)    # a = 45
    movzbl  -1(%rbp), %eax
    incl    %eax
    movb    %al, -2(%rbp)    # b = 45 + 1
    movb    $44, -3(%rbp)    # c = 44 (the math is done at compile time)
    movzbl  -1(%rbp), %eax   
    cmpb    -2(%rbp), %al
    jle     L2               
    movzbl  -2(%rbp), %eax
    movb    %al, -17(%rbp)
    jmp     L4
L2: 
    movzbl  -3(%rbp), %eax
    movb    %al, -17(%rbp)
L4:
    movzbl  -17(%rbp), %eax
    movb    %al, -4(%rbp)    # d = (a > b ? b : c)

这是没有开启优化的情况下。开启优化后,编译器将在编译时为您计算b和d,并硬编码它们的最终值(如果实际需要它们)。重点是gcc已经确定这里不会出现问题,因为所有可能的值都适合一个char
编辑:让我稍微修改一下。在赋值b时存在可能的错误,即使确定了也不会被编译器捕获。例如,如果b=a+250;,那么这肯定会溢出b,但gcc不会发出警告。这是因为对a的赋值是合法的,a是一个char,而且你需要自己确保数学运算在运行时不会溢出。

添加了GCC版本信息(4.3.2) - James Morris
所以你的意思是在4.3中,他们修复了我所称之为“编译器永远不会捕捉到它”的部分。因此,在使用常量的情况下,没有警告,但如果进行可能导致char溢出的数学运算,则会发出警告。听起来工作得很好,那还有问题吗? - Rob Napier
问题并不在于想要捕获溢出 - 我的代码已经经过测试并且在范围内。主要问题也不是关于为什么一些示例会提示警告而其他示例不会的原因。问题在于“修复所有警告”的理念,我有倾向想要实现它,但在-Wconversion标志的情况下,似乎完全没有必要在最简单的表达式中添加转换。这就是我想听取人们意见的领域。 - James Morris
好的,这很公平。是的,我完全同意使用-Wconversion和无警告策略。我认为答案是停止将枚举视为字符。它们的类型不是char;它是枚举。给你的枚举命名,并将变量设置为该类型。然后您将获得适当的类型检查,而且不需要经常进行转换。当您执行实际违反类型的操作时(例如在枚举上进行数学运算;它实际上不是数字,只是被实现为数字,对其进行数学运算可能不合法),您可能需要偶尔进行转换。 - Rob Napier

0
也许编译器已经能够看到所有的值都适合于 char 类型,因此它不会产生警告。我期望 `enum` 在编译的开始就被解析。

三目运算符的情况怎么样?这有意义吗? - James Morris
我认为编译器可以解决这个问题,只需将 d = 44 放入代码中。 - user181548

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接