11

私のコードでは、セマンティクスが変更された場合にスイッチを更新するのを忘れないように、次のようなアサートを含むフォールバックのデフォルト ケースを記述することに慣れています。

switch(mode) {
case ModeA: ... ;
case ModeB: ... ;
case .. /* many of them ... */
default: {
  assert(0 && "Unknown mode!");
  return ADummyValue();
}
};

人為的なフォールバック チェックのデフォルト ケースがジャンプ テーブルの生成に干渉するかどうか疑問に思っています。コンパイラがテーブルに最適化できるように、「ModeA」や「ModeB」などが連続していると想像してください。「デフォルト」ケースには実際の「return」ステートメントが含まれているため (リリース モードでアサートが消え、コンパイラーが return ステートメントの欠落についてうめき声を上げるため)、コンパイラーがデフォルト ブランチを最適化する可能性は低いようです。

これを処理する最良の方法は何ですか? 一部の友人は、未定義の動作が存在する場合にコンパイラが return ステートメントの欠落に関する警告を省略できるように、"ADummyValue" を null ポインター逆参照に置き換えることを勧めてくれました。これを解決するためのより良い方法はありますか?

4

7 に答える 7

3

少なくとも私が調べたコンパイラでは、答えは一般的にいいえです。それらのほとんどは、次のようなコードに switch ステートメントをコンパイルします。

if (mode < modeA || mode > modeLast) {
    assert(0 && "Unknown mode!");
    return ADummyValue();
}
switch(mode) { 
    case modeA: ...;
    case modeB: ...;
    case modeC: ...;
    // ...
    case modeLast: ...;
}
于 2010-11-25T16:07:53.317 に答える
3

コンパイラが MSVC の場合、__assume組み込みを使用できます: http://msdn.microsoft.com/en-us/library/1b3fsfxw(v=VS.80).aspx

于 2010-11-25T16:12:35.857 に答える
2

"default" (ha!) を使用している場合<assert.h>、とにかく定義は NDEBUG マクロに関連付けられているため、おそらく

    case nevermind:
#if !defined(NDEBUG)
    default:
        assert("can" && !"happen");
#endif
    }
于 2010-11-25T17:19:48.967 に答える
1

これを処理する最善の方法は、アサートを無効にしないことです。そうすれば、起こりうるバグにも注意を払うことができます。正確に何が起こったのかを説明する適切なメッセージを表示してアプリケーションをクラッシュさせてから、作業を続行する方がよい場合もあります。

于 2010-11-25T16:06:40.323 に答える
1

最適化が実際に妨げられた場合の解決策は 1 つしかありません。それは、悪名高い「#ifndef NDEBUG」がデフォルトのケースを回避することです。最高のトリックではありませんが、この状況では明らかです。

ところで: デフォルトのケースがある場合とない場合で、コンパイラが何を行うかを既に確認しましたか?

于 2010-11-25T16:00:51.297 に答える
1

絶対に到達してはならない状態がある場合は、プログラムを強制終了する必要があります。これは、リリース モードであっても、予期しない状態に到達したためです (もっと外交的で、実際にユーザー データを保存し、他のすべての優れた操作を行うことができます)。降りる前)。

また、マイクロ最適化が必要であることを (プロファイラーを使用して) 実際に測定していない限り、マイクロ最適化に執着しないでください。

于 2010-11-25T16:01:13.143 に答える
0

コンパイラ拡張機能を使用します。

// assume.hpp
#pragma once

#if defined _MSC_VER
#define MY_ASSUME(e) (__assume(e), (e) ? void() : void())
#elif defined __GNUC__
#define MY_ASSUME(e) ((e) ? void() : __builtin_unreachable())
#else   // defined __GNUC__
#error unknown compiler
#endif  // defined __GNUC__

-

// assert.hpp
#include <cassert>
#include "assume.hpp"

#undef MY_ASSERT
#ifdef NDEBUG
#define MY_ASSERT MY_ASSUME
#else   // NDEBUG
#define MY_ASSERT assert
#endif  // NDEBUG
于 2011-01-14T13:00:53.503 に答える