GCC中枚举开关的控制流分析不足

时间:2011-06-16 18:16:41

标签: c++ gcc gcc-warning control-flow

在以下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 ++中)。

你确定可以向枚举类型明确地转换一个任意整数常量,但不是那个被认为是未定义的行为吗?

4 个答案:

答案 0 :(得分:5)

问题是类型Test的变量可以具有编译器提供的类型所允许的任何值。因此,如果它确定它是一个32位无符号整数,则允许该范围内的任何值。因此,如果您致电foo(123456),则switch语句将无法捕获任何值,而return之后则没有switch

在您的交换机中添加default个案例或添加一些错误处理代码。

答案 1 :(得分:4)

虽然存在传递foo参数的实际危险,该参数不会触及任何return语句,但警告不依赖于枚举或危险。你可以在一个switch语句中看到与bool相同的效果,据我所知(完全可以说)完全不透水。

一般情况下,编译器不够智能,无法推断出您是否已涵盖控件实际可以通过switch语句的所有可能路径。为了那么聪明,它必须能够推断出程序在进入switch之前可以达到的所有可能状态,这直接导致暂停问题。

所以扣除必须在某个地方停止,并且(至少使用gcc)它会停止并确定没有默认情况,因此控制可能能够离开{{1} }没有点击switch

答案 2 :(得分:3)

无法保证变量test将包含有效的枚举,因此实际上您可以到达非空函数的末尾,例如如果您的调用代码如下所示:

Test test = Test(3);
foo(test);

答案 3 :(得分:1)

虽然您的enum只有三个声明的状态,但实现实际上会选择一个更大的整数类型(通常是int)来存储值,这些值不限于声明的值。标准只是做了一些最小的保证,以确保它至少可以处理指定的值和某些组合。有时这种自由是必不可少的,因为enum值旨在按位求和以形成组合。因此,实际上可以使用foo来调用函数Test(3),这在return中找不到switch语句。