在以下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 ++中)。
你确定可以向枚举类型明确地转换一个任意整数常量,但不是那个被认为是未定义的行为吗?
答案 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
语句。