为什么即使type_t
处理了所有可能的值,此代码也会触发"控制到达非void函数的结尾" ?处理此警告的最佳方法是什么?return -1
在切换后添加一个?
(此处测试代码)
typedef enum { A, B } type_t; int useType(type_t x) { switch (x) { case A: return 0; case B: return 1; } }
一般来说,enum
s不是唯一的.有人可以像你这样调用你的函数useType( (type_t)3 );
.这在C++ 14 [dcl.enum]/8中具体提到:
可以定义具有未由其任何枚举器定义的值的枚举.
现在,有一系列规则确切地指出哪些其他值可能用于其他类型的枚举.
有两类枚举.第一种是 固定的基础类型,例如enum type_t : int
,或enum class type_t
.在这些情况下,基础类型的所有值都是有效的枚举器.
第二种不是固定的底层类型,它包括像你这样的预C++ 11枚举.在这种情况下,可以通过以下方式总结关于值的规则:计算为了存储枚举的所有值所需的最小位数; 那么在该位数中可表示的任何数字都是有效值.
所以-在特定情况下,单个位可以容纳两个值A
和B
,因此3
不是枚举有效值.
但是如果你的枚举是A,B,C
,那么即使3
没有具体列出,它也是上述规则的有效值.(所以我们可以看到几乎所有的枚举都不是排他性的).
现在我们需要查看规则,了解如果有人确实尝试转换3
为会发生什么type_t
.转换规则是C++ 14 [expr.static.cast]/10,它表示生成了未指定的值.
但是,CWG 1766号文件承认C++ 14文本存在缺陷,并将其替换为以下内容:
可以将整数或枚举类型的值显式转换为完整的枚举类型.如果原始值在枚举值(7.2)的范围内,则该值不变.否则,行为未定义.
因此,在你正好有两个普查员与价值的具体情况0
和1
,没有其他价值是不可能的,除非该计划已经引发未定义行为,所以警告,可能会被认为是假阳性.
要删除警告,请添加执行某项操作的default:
案例.为了防御性编程,我还建议,无论如何都有一个默认情况是个好主意.在实践中,它可能用于"包含"未定义的行为:如果有人确实传递了无效值,那么您可以干净地抛出或中止.
注意:关于警告本身:编译器不可能准确地警告控制流是否会到达函数的末尾,因为这需要解决停止问题.
他们倾向于谨慎行事:如果编译器不完全确定,则会发出警告,这意味着存在误报.
因此,此警告的存在并不一定表明可执行文件实际上允许进入默认路径.