10

在以下 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: 错误:从 'int' 到 'Test' 的无效转换
> test.cpp:15:14: 错误:初始化 'int foo(Test)' 的参数 1

因为 12354 不是一个有效值Test(尽管它在纯C确实有效,但它不在 C++ 中)。

您确实可以将任意整数常量显式转换为枚举类型,但这不被认为是未定义的行为吗?

4

4 回答 4

5

问题是类型变量Test可以具有编译器给它的类型所允许的任何值。因此,如果它决定它是一个 32 位无符号整数,则允许该范围内的任何值。因此,例如,如果您调用foo(123456),您的switch语句将不会捕获任何值,并且return您的switch.

default在您的开关中放置一个案例或添加一些错误处理代码。

于 2011-06-16T18:22:57.780 回答
4

foo尽管传递不会影响任何return语句的参数存在实际危险,但警告不依赖于枚举或危险。您可以在 switch 语句中看到相同的效果bool,该语句(据我所知)完全无懈可击。

一般来说,编译器不够聪明,无法推断您是否已经涵盖了控制实际上可以通过switch语句执行的所有可能路径。要变得如此聪明,它必须能够推断出程序在进入 之前可以达到的所有可能状态switch,这直接导致了停机问题。

因此,推论必须在某处停止,并且(至少在 gcc 中)它在确定没有默认情况时停止,因此控制可能能够在switch不命中的情况下离开return.

于 2011-06-16T18:43:30.703 回答
3

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

Test test = Test(3);
foo(test);
于 2011-06-16T18:21:36.050 回答
1

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

于 2011-06-16T18:25:23.623 回答