C中的Typesafe枚举?

dru*_*rum 7 c enums

如果我有多个enum,例如:

 enum Greetings{ hello, bye, how };

 enum Testing { one, two, three };
Run Code Online (Sandbox Code Playgroud)

如何强制使用正确的enum?例如,我不希望有人hello在他们应该使用时使用它们以one获得更好的调试和可读性.

Die*_*Epp 12

在C中,您可以使用样板代码伪造它.

typedef enum { HELLO_E, GOODBYE_E } greetings_t;
struct greetings { greetings_t greetings; };
#define HELLO ((struct greetings){HELLO_E})
#define GOODBYE ((struct greetings){GOODBYE_E})

typedef enum { ONE_E, TWO_E } number_t;
struct number { number_t number; };
#define ONE ((struct number){ONE_E})
#define TWO ((struct number){TWO_E})

void takes_greeting(struct greetings g);
void takes_number(struct number n);

void test()
{
    takes_greeting(HELLO);
    takes_number(ONE);

    takes_greeting(TWO);
    takes_number(GOODBYE);
}
Run Code Online (Sandbox Code Playgroud)

这不应该产生任何开销,并产生错误而不是警告:

$ gcc -c -std=c99 -Wall -Wextra test2.c
test2.c: In function ‘test’:
test2.c:19: error: incompatible type for argument 1 of ‘takes_greeting’
test2.c:20: error: incompatible type for argument 1 of ‘takes_number’

请注意,我没有使用GNU扩展,也没有生成虚假警告.只有错误.另请注意,我使用的是一种与泥土一样古老的GCC版本,

$ gcc --version
powerpc-apple-darwin9-gcc-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5493)
Copyright (C) 2005 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

这适用于任何支持C99复合文字的编译器.

  • 这很整洁,但确实使在 switch 语句中使用枚举有点难看。 (3认同)

Bil*_*nch 8

Clang产生以下警告,这是您可以做的最好的事情(虽然用户可以将警告升级为错误).

enum Greetings { hello, bye, how };
enum Count { one, two, three };

void takes_greeting(enum Greetings x) {}
void takes_count(enum Count x) {}

int main() {
    takes_greeting(one);
    takes_count(hello);
}
Run Code Online (Sandbox Code Playgroud)

编译器输出:

cc     foo.c   -o foo
foo.c:8:17: warning: implicit conversion from enumeration type 'enum Count' to different enumeration type 'enum Greetings' [-Wenum-conversion]
        takes_greeting(one);
        ~~~~~~~~~~~~~~ ^~~
foo.c:9:14: warning: implicit conversion from enumeration type 'enum Greetings' to different enumeration type 'enum Count' [-Wenum-conversion]
        takes_count(hello);
        ~~~~~~~~~~~ ^~~~~
Run Code Online (Sandbox Code Playgroud)

如果用户要忽略编译器中的错误和警告,那么您无法帮助他们.

  • 遗憾的是,gcc在C模式下不会产生类似的警告.我不知道msvc是否有.关于如何欺骗gcc,有一些评论[这里](http://stackoverflow.com/questions/4669454/how-to-make-gcc-warn-about-passing-wrong-enum-to-a-function)以可读性为代价制作警告. (3认同)