web-dev-qa-db-ja.com

assert(0)はどういう意味ですか?

私の試験の1つでこのような質問がありましたが、まだどのように答えればよいかわかりません。アサーションはプログラムをテストする方法であることを理解していますが、assert(0)がチェックしていることはあまりわかりません。これはトリックの質問ですか?常に失敗しますが、その理由はわかりません。何をチェックしていますか?

どんな説明でも素晴らしいでしょう、ありがとう。

26
Smith Western

常に失敗します。それはほとんどそれです。 x = 5の場合は常に「assert(x == 5)」が成功するのと同じ理由で失敗します。

applicationを要求している場合、実際には発生しないはずのコードブロックに配置します。

switch(suit) {
  case CLUB:
  case DIAMOND:
  case HEART:
  case SPADE:
  // ...
  default:
    assert(0);
 }
12
djechlin

C++標準は、assertの定義をC標準に委ねています。

assertマクロは、診断テストをプログラムに入れます。 void式に展開されます。実行時に、expression(スカラー型でなければならない)がfalse(つまり、0に等しい)である場合、assertマクロは失敗した特定の呼び出しに関する情報を書き込みます(引数のテキスト、ソースファイルの名前、ソース行番号、囲んでいる関数の名前を含みます。後者はそれぞれ前処理マクロ___FILE___および___LINE___の値です。実装定義形式の標準エラーファイルの識別子___func___)。次に、abort関数を呼び出します。


assert(0)では、_0_はfalseとして解釈されるため、このアサーションは常に失敗するか、またはfire 、アサーションチェックがオンの場合。

したがって、それは

「実行がこのポイントに達することはありません。」

実際には、実行が特定のポイントに到達するか到達しないかについてコンパイラーを黙らせるのは困難です。多くの場合、コンパイラは最初に、値を返さずに関数の最後に到達する可能性について最初に文句を言います。そこにassert(0)を追加すると、理想的にはその問題を解決するはずですが、コンパイラはassertについて文句を言うか、警告しようとしていることにすでに気付いていると言っていることに気付かない場合があります。

(1)可能な対策は、その時点で例外もスローすることです。

_auto foo( int x )
    -> int
{
    if( x == 1 ) { return 42; }
    assert( 0 ); throw 0;       // Should never get here!
}
_

もちろん、そのダブルワーミーは、より高いレベルのマクロとして定義できます。例外の種類については、_std::exception_ではなく、通常のcatchによってキャッチされることを意図した例外ではないため、そのままにしておくことができます。または、標準の例外階層を信頼する場合(私には意味がありませんが)、_std::logic_error_を使用できます。


assertアサーションチェックをオフにするには、_<assert.h>_を含める前にシンボルNDEBUGを定義できます。

このヘッダーには特別なサポートがあるため、NDEBUGが定義されているかどうかに関係なく、複数回含めることができます。

翻訳単位には、ライブラリヘッダーを任意の順序で含めることができます(第2項)。 _<cassert>_または_<assert.h>_を含めることの効果は、毎回NDEBUGの字句的に定義されたものに依存することを除いて、それぞれを複数回含めることができます。 。

上記のダブルワミーの合理的な定義は、インクルードガードのないNDEBUGにも依存します。

assert_should_never_get_here.hpp
_#include <stdexcept>        // std::logic_error
#include <assert.h>

#undef ASSERT_SHOULD_NEVER_GET_HERE
#ifdef NDEBUG
#   define ASSERT_SHOULD_NEVER_GET_HERE() \
        throw std::logic_error( "Reached a supposed unreachable point" )
#else
#   define ASSERT_SHOULD_NEVER_GET_HERE() \
        do{ \
            assert( "Reached a supposed unreachable point" && 0 ); \
            throw 0; \
        } while( 0 )
#endif
_

免責事項:2000年代前半に何度もコーディングしましたが、この答えのために上記のコードを作成しましたが、g ++でテストしましたが、必ずしも完璧ではないかもしれません。


(1) 別の可能性、g ++固有の組み込み____builtin_unreachable_については、 Basile Starynkevitchの答え を参照してください。

30

はい、常に失敗します。

assert(0)またはassert(false)は通常、到達不能コードをマークするために使用されるため、デバッグモードでは診断メッセージが出力され、到達不能と思われる場合にプログラムが中止されます。実際に到達しました。これは、プログラムが想定どおりに動作していないことを示す明確なシグナルです。

9
emlai

他の回答(特に this one)へのadditionで、最近の [〜#〜] gcc [〜#〜]を使用している場合 (または Clang )、 GCCビルトイン 、特に__builtin_unreachable()の代わりにassert(0)を使用することを検討できます。

いくつかの違いがあります:最初に、assert-DNDEBUGで無効にできます。そして、__builtin_unreachableは、コンパイラがコードを最適化する方法を変更します。

もちろん、一部のコンパイラは__builtin_unreachableについて知りません。

また、[[noreturn]] C++関数(C++ 11以降)の呼び出しを検討することもできます-または __attribute__((noreturn)) for [〜#〜] gcc [〜#〜]abort()など

ところで、assert(0)は、例外をスローするのとまったく同じではありません(例外をキャッチできるため)