GCC中enum switch控制流分析不足
在以下 C++ 代码中:
typedef enum { a, b, c } Test;
int foo(Test test) {
switch (test) {
case a: return 0;
case b: return 1;
case c: return 0;
}
}
使用 -Wall
编译时发出警告,表示控制到达非 void 函数的末尾。为什么?
编辑
示例中的变量 test
可以包含任何值通常是不正确的。
foo(12354)
无法编译:
> test.cpp:15:14: error: invalid conversion from ‘int’ to ‘Test’ > test.cpp:15:14: error: initializing argument 1 of ‘int foo(Test)’
因为 12354 不是有效的 Test
值(尽管它确实在普通 中会有效) C,但不是 C++)。
您确实可以将任意整数常量显式转换为枚举类型,但这不是被视为未定义行为吗?
In the following C++ code:
typedef enum { a, b, c } Test;
int foo(Test test) {
switch (test) {
case a: return 0;
case b: return 1;
case c: return 0;
}
}
a warning is issued when compiling with -Wall
, saying that control reaches end of non-void function. Why?
Edit
Its not generally correct to say that the variable test
in the example can contain any value.
foo(12354)
does not compile:
> test.cpp:15:14: error: invalid conversion from ‘int’ to ‘Test’ > test.cpp:15:14: error: initializing argument 1 of ‘int foo(Test)’
because 12354 isn't a valid Test
value (though it indeed would be valid in plain C, but it's not in C++).
You sure could explicitly cast an arbitrary integer constant to the enum type, but isn't that considered Undefined Behaviour?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
尽管向
foo
传递一个不会命中任何return
语句的参数确实存在危险,但警告并不依赖于枚举或危险。 您可以在 switch 语句中使用bool
看到相同的效果,据我所知,它是完全无懈可击的。一般来说,编译器不够智能,无法推断出您是否已经覆盖了控件实际上可以通过
switch
语句采取的所有可能路径。为了变得如此聪明,它必须能够推断出程序在进入开关之前可以达到的所有可能状态,这直接导致了停止问题。因此,推导必须在某个地方停止,并且(至少对于 gcc)它会在确定不存在默认情况时停止,因此控制可能能够离开
开关
无需点击返回
。Although there is actual danger of passing
foo
an argument that will not hit any of thereturn
statements, the warning does not depend on enum, or on the danger. You can see the same effect withbool
, in a switch statement which is (as far as I can tell) completely watertight.In general the compiler isn't smart enough to deduce whether you've covered every possible path that control could actually take through the
switch
statement. To be that smart it would have to be able to deduce all of the possible states the program can reach before entering theswitch
, which leads straight to the Halting Problem.So the deduction has to stop somewhere, and (at least with gcc) it stops with the determination that there is no default case and that therefore control might be able to leave the
switch
without hittingreturn
.无法保证变量
test
将包含有效的枚举,因此实际上您有可能到达非 void 函数的末尾,例如,如果您的调用代码如下所示:There is no guarantee that the variable
test
will contain a valid enum so it is in fact possible for you to reach the end of your non-void function, e.g. if your calling code looks like this:虽然您的枚举只有三个声明状态,但实现实际上会选择一个更大的整型(通常是 int)来存储值,这些值不限于声明的状态。该标准只是做出一些最低限度的保证,以确保它至少可以处理指定的值和某些组合。有时这种自由是必不可少的,因为枚举值旨在按位或组合在一起以形成组合。因此,实际上可以使用
Test(3)
来调用函数foo
,但在Return
语句中找不到return
语句>切换。Although your
enum
has only three declared states, the implementation will actually choose a larger integral type (typically int) to store the values, which are NOT restricted to those declared. The Standard just makes some minimal guarantees to ensure it can at least handle the values specified and certain combinations. Sometimes this freedom is essential, as theenum
values are intended to be bitwise-ORed together to form combinations. So, the functionfoo
can actually be called with say,Test(3)
, which wouldn't find areturn
statement in yourswitch
.问题是
Test
类型的变量可以具有编译器赋予它的类型允许的任何值。因此,如果它确定它是 32 位无符号整数,则允许该范围内的任何值。因此,如果您调用foo(123456)
,您的switch
语句将不会捕获任何值,并且之后不会有
return
开关。在您的开关中放置一个
default
案例或添加一些错误处理代码。The problem is that a variable of type
Test
can have any value allowed by the type the compiler gives it. So if it decided it was a 32-bit unsigned integer, any value in that range is allowed. So, if for instance you callfoo(123456)
, yourswitch
statement will not catch any value and there's noreturn
after yourswitch
.Put a
default
case in your switch or add some error-handling code.