"control reaches end of non-void function",通过枚举类型进行完全处理的案例切换
"control reaches end of non-void function" with fully handled case switch over an enum type
为什么即使处理了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;
}
}
相关:检测将int强制转换为枚举是否会导致非枚举值
一般来说,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,它表示生成一个未指定的值。
然而,《化学武器公约》第1766期承认C++14文本有缺陷,并将其替换为以下内容:
整型或枚举类型的值可以显式转换为完整的枚举类型。如果原始值在枚举值(7.2)的范围内,则该值保持不变。否则,行为未定义
因此,在您的特定情况下,正好有两个值为0
和1
的枚举器,除非程序已经触发了未定义的行为,否则不可能有其他值,因此该警告可能被视为误报。
要删除警告,请添加一个有作用的default:
事例。我还建议,为了防御编程的利益,无论如何,有一个默认情况是个好主意。在实践中,它可能会"包含"未定义的行为:如果有人碰巧传递了一个无效值,那么你可以干净地抛出或中止。
注意:关于警告本身:编译器不可能在控制流到达函数末尾时准确地发出警告,因为这需要解决停止问题。
他们倾向于谨慎行事:如果不完全确定,编译器会发出警告,这意味着存在误报。
因此,此警告的存在并不一定表明可执行文件实际上允许进入默认路径。
回答第二个问题("处理此警告的最佳方法是什么?"):
在我看来,最好的方法通常是在switch语句之后添加对__builtin_unreachable()
的调用(在GCC和Clang中都可用——也许在某个时候我们会得到[[unreachable]]
)。通过这种方式,您可以明确地告诉编译器,代码永远不会在switch语句上运行。如果真的发生了,你很乐意接受未定义行为的所有可怕后果。请注意,最明显的溢出原因是一个包含未列出值的枚举——正如@M.M.在回答中指出的那样,这无论如何都是未定义的行为
通过这种方式,您可以消除GCC和Clang当前版本上的警告,而不引入新的警告。如果您错过了在switch语句上运行的有效情况,那么您将失去编译器的保护。这在一定程度上得到了缓解,GCC和Clang都会警告您,如果完全错过了开关情况(例如,如果将值添加到枚举中),但如果其中一个情况遇到break
语句,则不会发出警告。
- 警告处理为错误这里有什么问题
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 处理多个异常集合的C++方法
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 使用流处理接收到的数据
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 基于多个条件处理地图中的所有元素
- 如何用数字处理log(0)
- SSL上的`curl_easy_send`和`curl_asy_recv`:如何处理`CURLE_AGAIN`
- 错误处理.将系统错误代码映射到泛型
- 从文本文件中读取时钟时间和事件时间并进行处理
- 在运行时处理类型擦除的数据-如何不重新发明轮子
- 在for循环中使用auto vs decltype(vec.size())来处理字符串的向量
- 用于矢量处理的多个线程
- 对字符串进行排序时,在c++中处理sort()
- 处理3D数组的边缘和角案例的方法
- 处理多个标志案例
- "control reaches end of non-void function",通过枚举类型进行完全处理的案例切换
- 案例研究:图像处理中的多态性