如何让gcc警告将错误的枚举传递给函数

Roc*_*net 23 enums gcc gcc-warning

gcc似乎没有使用以下代码生成警告.如何让它产生警告?

typedef enum
{
    REG8_A,
    REG8_B,
    REG8_C
}REG8;

typedef enum
{
    REG16_A,
    REG16_B,
    REG16_C
}REG16;

void function(REG8 reg8)
{

}

int main(void)
{
    function(REG16_A);    // Should warn about wrong enum
}
Run Code Online (Sandbox Code Playgroud)

Bra*_*din 9

有关使用GCC在C中执行此操作的方法-Wenum-compare(如果启用则默认启用-Wall),必须先对枚举常量执行比较,然后再将其传递给函数以获得所需的诊断.

-Wenum-比较

警告不同枚举类型的值之间的比较.在C++中,还会诊断条件表达式中的枚举不匹配,并且默认情况下会启用警告.在C中,此警告由-Wall启用.

http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html

因为这种比较碰巧在我们调用函数时自动发生,我们可以将函数包装在宏中.为了便于阅读,我还定义了一个宏SAFE_ENUM,它对枚举常量执行无害的比较(这是在尝试将错误的枚举常量传递给fooor 时最终触发警告的内容bar).

/**
  SAFE_ENUM: evaluate an enumeration constant safely
  TYPE: the enumeration type
  VAL: the enumeration constant to evaluate
*/
#define SAFE_ENUM(TYPE, VAL) ((VAL) == (TYPE)0 ? (VAL) : (VAL))

typedef enum
{
    REG8_DEFAULT,
    REG8_A,
    REG8_B,
    REG8_C
} Reg8;

typedef enum
{
    REG16_DEFAULT,
    REG16_A,
    REG16_B,
    REG16_C
} Reg16;

void foo(Reg8 reg8)
#define foo(reg8) foo(SAFE_ENUM(Reg8, reg8))
{
    printf("%s called with value %d\n", __func__, reg8);
}

void bar(Reg16 reg16)
#define bar(reg16) bar(SAFE_ENUM(Reg16, reg16))
{
    printf("%s called with value %d\n", __func__, reg16);
}

int main(void)
{
    foo(REG8_A);  // ok
    bar(REG16_A); // ok
    foo(REG16_B); // warning
    bar(REG8_B);  // warning

    Reg16 a_reg16 = 42;
    foo(a_reg16); // warning: foo requires a Reg8 but you gave it a Reg16
}
Run Code Online (Sandbox Code Playgroud)

  • +1因为这是个好主意,不幸的是当它与枚举变量一起使用时它不起作用,这将在没有警告的情况下编译:`Reg16 reg = 42; 巴(REG);` (2认同)

uli*_*tko 8

这种行为的原因是您使用的是C编译器而不是C++.并且在C enum类型中不是真正的类型,C中的枚举只保存int常量,并且它们可以自由地与任何整数和任何算术混合.

在C++中,而不是你有真正的枚举,你会这样想他们,语言标准作为传达发生所需要的类型检查.

您的问题可以通过两种方式解决:

  • 使用C++编译器.

    这样你就可以得到真正的枚举,就像你想要的那样.

  • 将代码更改为纯C样式,即不使用枚举,因为在C中它们只是常量集,编译器只能帮助您对常量值进行排序.在C中,将负责保持传递常量的"类型"一致.再一次:对于C,枚举成员只是int常量,你不能让它们输入.


#define REG8_A 0
#define REG8_B 1
#define REG8_C 2

#define REG16_A 0
#define REG16_B 1
#define REG16_C 2
Run Code Online (Sandbox Code Playgroud)

  • Clang 警告(`-Wenum-conversion`),并且此标志已添加到 gcc trunk(非默认),因此我相信您可以期望它在 gcc-10 中工作。https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78736#c14 (2认同)

Pau*_*l R 6

我能看到生成警告的唯一方法是,如果你准备传递指针而不是裸露的枚举,例如

typedef enum
{
    REG8_A,
    REG8_B,
    REG8_C
} REG8;

typedef enum
{
    REG16_A,
    REG16_B,
    REG16_C
} REG16;

void function(REG8 * reg8)
{

}

int main(void)
{
    REG16 r = REG16_A;
    function(&r);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

不完全是一个优雅的解决方案,但它确实发出了警告,至少有gcc -Wall:

$ gcc -Wall warn_enum.c -o warn_enum
warn_enum.c: In function ‘main’:
warn_enum.c:23: warning: passing argument 1 of ‘function’ from incompatible pointer type
$
Run Code Online (Sandbox Code Playgroud)