【问题标题】:How to deal with -Wconversion warnings from GCC?如何处理来自 GCC 的 -Wconversion 警告?
【发布时间】:2009-10-29 12:58:21
【问题描述】:

我正在使用 GCC 的 -Wconversion 警告标志构建我的项目。 (gcc (Debian 4.3.2-1.1) 4.3.2) 在 64 位 GNU/Linux 操作系统/硬件上。我发现它有助于确定我在哪里混合了类型或不清楚应该使用哪些类型。

在激活它的警告的大多数其他情况下,它并没有太大帮助,我在问我打算如何处理这些:

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) 投射所有这些以防止警告是否过度设计?

Edit2:一些额外的案例(继上述案例之后):

a += A;         /* warning converting from int to char */
a++;            /* ok */
a += (char)1;   /* warning converting from int to char */

除此之外,我的问题是主观的,当您认为某些开发人员主张删除所有警告时,我想听听其他人如何处理此类情况下的转换警告.

YAE:

一种可能的解决方案是只使用ints 而不是chars,对吗?实际上,它不仅需要更多内存,而且速度也较慢,如以下代码所示。使用-Wconversion 构建时,数学表达式只是为了获得警告。由于转换,我假设使用 char 变量的版本会比使用 ints 的版本运行得慢,但在我的(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;
}

-DUSE_INT 传递给gcc 以构建上述sn-p 的int 版本。

【问题讨论】:

  • 用 A > 255 编译时是什么意思?
  • 对于A = 256char a = A 带有“警告:隐式常量转换中溢出”,char c = B - 2 带有“警告:转换为‘char’会改变‘int’常量值”

标签: c gcc compiler-warnings


【解决方案1】:

当你说/* 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 的赋值是合法的,achar,而确保数学在运行时不会溢出是你(而不是编译器)的问题。

【讨论】:

  • 添加 GCC 版本信息 (4.3.2)
  • 所以你的意思是,在 4.3 中,他们已经修复了我所说的“编译器永远不会捕获它”。因此,在使用常量的情况下,没有警告,但如果您进行可能溢出字符的数学运算,它们会发出警告。听起来它运作良好,然后。还有问题吗?
  • 问题不在于想要捕获溢出 - 我的代码已经过测试并且在范围内。主要问题也不是为什么一些例子会提示警告而其他例子没有。问题在于我倾向于想要实现的“修复所有警告”理念,但在 -Wconversion 标志的情况下,似乎完全 OTT 将最简单的表达式乱扔垃圾。我想听听人们对这个领域的看法。
  • 好的,这很公平。是的,我完全同意使用 -Wconversion 和无警告政策。我相信的答案是停止将您的枚举视为字符。它们的类型不是字符;它是枚举。命名您的枚举,并使您的变量成为该类型。然后您将获得正确的类型检查,并且不需要经常转换。当你做一些实际上违反类型的事情时,你可能需要偶尔进行强制转换(比如对枚举进行数学运算;它不是真正的数字,它只是作为一个实现,对它的数学运算可能不合法)。
【解决方案2】:

也许编译器已经可以看到所有值都适合一个字符,所以它不会打扰警告。我希望enum 在编译开始时就被解决。

【讨论】:

  • 三元运算符的情况呢?这有什么意义?
  • 我认为编译器可以解决这个问题,所以它只输入d = 44
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-29
  • 2014-11-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多