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ない引数を渡すという実際の危険性はありますが、警告は列挙型や危険性に依存しません。(私が知る限り)完全に水密であるswitchステートメントで、と同じ効果を見ることができます。returnbool

switch一般に、コンパイラーは、コントロールがステートメントを実際に通過する可能性のあるすべてのパスをカバーしたかどうかを推測するほど賢くはありません。そのように賢くするには、プログラムがに入る前に到達できる可能性のあるすべての状態を推測できなければなりませんswitch。これは、停止問題に直接つながります。

したがって、推論はどこかで停止する必要があり、(少なくともgccでは)デフォルトのケースがないため、コントロールがヒットせずにを離れることができる可能性があるという判断で停止します。switchreturn

于 2011-06-16T18:43:30.703 に答える
3

変数に有効な列挙型が含まれるという保証はないtestため、実際には void 以外の関数の最後に到達する可能性があります。たとえば、呼び出しコードが次のようになっている場合です。

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

宣言された状態は 3 つしかありませんがenum、実際には、宣言されたものに制限されない値を格納するために、実装によってより大きな整数型 (通常は int) が選択されます。標準は、少なくとも指定された値と特定の組み合わせを処理できることを保証するために、いくつかの最小限の保証を行います。enum組み合わせを形成するために値をビットごとに OR 演算することが意図されているため、この自由が不可欠な場合があります。したがって、関数fooは実際には say, で呼び出すことができますが、これはyour にステートメントがTest(3)見つかりません。returnswitch

于 2011-06-16T18:25:23.623 に答える