gpt4 book ai didi

c - 如何处理纯 C 中的严格枚举?

转载 作者:行者123 更新时间:2023-12-05 06:47:46 25 4
gpt4 key购买 nike

看看下面的代码:

typedef enum {
A, B, C
} Foo;

int foo(Foo x) {
switch(x) {
case A: return 1;
case B: return 2;
case C: return 3;
}
}

GCC 10.2 输出

<source>:11:1: warning: control reaches end of non-void function [-Wreturn-type]
11 | }
| ^

这是因为我可以将 42 之类的东西传递给 foo,而不仅仅是 ABC >。所以问题是:如何告诉 GCC 只有 ABC 可以被 switch 语句处理,否则行为是不明确的?可以接受特定于编译器的功能。

让我指出一些我不满意的解决方案。首先,我可以只插入 default: __builtin_unreachable(); 但这会渗透案例分析:想象一下,显然我正在添加 D 变体,而编译器不会告诉我D 未处理。

其次,我可以插入 if (x > C) { __builtin_unreachable(); } 在 switch 语句之前,但这太不可能了,因为 switch(x) 实际上是由一个不知道 Foo 变体的宏生成的,它只知道一些变量 x

第三,我可以插入 #pragma GCC diagnostic ignored "-Wreturn-type",但同样,switch(x) 是由宏生成的,这就是为什么我无法通过 #pragma GCC diagnostic pop 将诊断恢复到之前的状态。

第四,我可以使用数组代替 switch,但返回的表达式不是常量,是由生成 switch(x) 的宏的用户提供的。

最后一个:我可以在 switch 语句之后写 return 42; 但我还是想在生成 switch(x) 的宏中自动禁用警告,因为它在我的代码库中被广泛使用。

Godbolt

最佳答案

如果您想进行一些轻微的自虐,您可以使用 setjmplongjmp 粗略地实现类似异常的行为:

#include <stdlib.h>
#include <setjmp.h>
#include <stdio.h>

typedef enum Foo {
A, B, C
} Foo;

#define ENUM_OUT_OF_RANGE -1

jmp_buf env;

int foo( Foo x )
{
switch ( x )
{
case A: return 1;
case B: return 2;
case C: return 3;
default: longjmp( env, ENUM_OUT_OF_RANGE ); // "throw" ENUM_OUT_OF_RANGE
}
}

int main( void )
{
int ex;

if ( (ex = setjmp( env )) == 0 ) // "try" block
{
Foo arr[] = {A, B, C, 42};

for ( size_t i = 0; i < 4; i++ )
{
printf( "value of %d = %d\n", arr[i], foo( arr[i] ) );
}
}
else // "catch" block
{
if ( ex == ENUM_OUT_OF_RANGE )
{
fprintf( stderr, "foo was called with a value outside the range of Foo\n" );
}
}

return 0;
}

构建时没有如下警告(至少在我的系统上是这样):

gcc -o exceptions -std=c11 -pedantic -Wall -Werror exceptions.c

输出:

$ ./exceptions 
value of 0 = 1
value of 1 = 2
value of 2 = 3
foo was called with a value outside the range of Foo

关于c - 如何处理纯 C 中的严格枚举?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66972588/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com