「アサート」機能とは何ですか?


262

私はOpenCVチュートリアルを研究していて、そのassert機能に出くわしました。それは何をするためのものか?


20
男のアサートからノートを注意してください:「アサートを()マクロとして実装され、テスト式が副作用を持っている場合、プログラムの動作はNDEBUGが定義されているかどうかによって異なります。これは、オンになっているデバッグするときに離れて行く特異なバグを作成することができます。 」
ヨハネスシャウブ-litb 2009年


35
@ S.Lottは、Googleを検索するユーザーがこのページを上位の検索結果の1つとして見つけ、質問に対する適切な査読済み回答を提供し、同時にスタックオーバーフローを促進するため、私からの+1になります。
Matt

6
私からの-1です。最上位の検索結果は、OPが最初に参照すべきドキュメントであるはずです。
オービットのライトネスレース

9
@LightnessRacesinOrbit。私を怠惰と呼んでください、しかし私はあなたのような知識のあるSOユーザーが提供する文書の読みを凝縮、要約、説明した優れたものを使うことを好みます。私の心からの感謝:)
タイソンヒル

回答:


298

assert引数がfalseであることが判明した場合、プログラムは(通常、assertステートメントを引用するメッセージで)プログラムを終了します。予期しない状況が発生した場合にプログラムをより明確に失敗させるために、デバッグ中に一般的に使用されます。

例えば:

assert(length >= 0);  // die if length is negative.

次のように失敗した場合に表示される、より有益なメッセージを追加することもできます。

assert(length >= 0 && "Whoops, length can't possibly be negative! (didn't we just check 10 lines ago?) Tell jsmith");

または、このように:

assert(("Length can't possibly be negative! Tell jsmith", length >= 0));

リリース(デバッグではない)ビルドを行う場合、通常はコンパイラスイッチを使用してマクロをassert定義することにより、ステートメントを評価するオーバーヘッドを取り除くこともできますNDEBUG。これの当然の結果は、プログラムが実行中のassertマクロに依存してはならないということです。

// BAD
assert(x++);

// GOOD
assert(x);    
x++;

// Watch out! Depends on the function:
assert(foo());

// Here's a safer way:
int ret = foo();
assert(ret);

アサートは、abort()を呼び出すプログラムと何もしないことが保証されていない組み合わせから、ユーザーが文字ではなく数値を入力するのではなく(たとえば、他の方法で処理されます)。


49
assert通常は例外が発生します」-C ++では、「例外」は発生しませんが、アボートを呼び出します...少し異なります。
Artyom

5
この回答は、質問にタグが付けられている言語と同じだとは思わない(CおよびC ++)。CおよびC ++では、assertは例外を発生させず、引数を括弧で囲み、#文字はコメントを導入しません。
スティーブジェソップ

選択肢は次のとおりです。コミュニティWikiに回答して、質問を編集して古いものを削除し、他のユーザーに正しい情報を配置するよう依頼します。このようにして、反対投票は担当者に影響を与えず、人々は回答を改善できます。
ヨハネスシャウブ-litb 2009年

2
lengthがNaNの場合、length> = 0もfalseになります
Andreas

1
現在、VS 2015では、エラーメッセージのあるアサートは故障しているため機能しません。それはあるはずですassert("error message", expression)
Dooskington

102

アサートコンピュータ文は、文と類似していることを確認してください英語インチ


131
まあ、そうではありません。「ライトがオフになっていることを確認する」とは、「ライトをチェックして、オンになっている場合はオフにする」ことを意味します。「ダブルチェック」はより近い翻訳だと思います。
ルークモーラー、

7
@Lukeは、英語が同じことを言うための多くの方法を提供するという点で、英語の驚異を示しています。ただし、assert(length> 0)を検討してください。したがって、「長さがゼロより大きいことを再確認するまたは「長さがゼロより大きいことを確認する」に変換できます。両方のオプションが機能することは明らかですが、私は私のものを好みます;)
Blake7

4
まあ、しかし、他の解釈は、「ある作る長さがゼロよりも大きいです。」ですから、もう少しあいまいさがあります。
ルーク・モーラー2014

29
英語の動詞 "assert"に似ています
Steve Carter

確かに、「確認する」は「チェックし、大丈夫でなければ変更する」と解釈できます。
Erik Bongers

14

を見てみましょう

C ++のassert()サンプルプログラム

多くのコンパイラーは、assert()マクロを提供しています。assert()マクロは、パラメーターがTRUEと評価された場合にTRUEを返し、FALSEと評価された場合に何らかのアクションを実行します。多くのコンパイラは、assert()が失敗するとプログラムを中止します。他は例外をスローします

assert()マクロの強力な機能の1つは、DEBUGが定義されていない場合、プリプロセッサがマクロをコードなしに折りたたむことです。これは開発中の大きな助けとなり、最終製品が出荷されるときに、パフォーマンスの低下やプログラムの実行可能バージョンのサイズの増加はありません。

例えば

#include <stdio.h>
#include <assert.h>

void analyze (char *, int);

int main(void)
{
   char *string = "ABC";
   int length = 3;

   analyze(string, length);
   printf("The string %s is not null or empty, "
          "and has length %d \n", string, length);
}

void analyze(char *string, int length)
{
   assert(string != NULL);     /* cannot be NULL */
   assert(*string != '\0');    /* cannot be empty */
   assert(length > 0);         /* must be positive */
}

/****************  Output should be similar to  ******************
The string ABC is not null or empty, and has length 3

11
「NDEBUGが定義されている場合」ではないのですか?
RichN

2
その「多くのコンパイラ」とは何ですか?MSVCとGCCはどちらもこれに準拠した標準です。非準拠のコンパイラー:アサートはありません。メッセージを出力せず、アサートが失敗したときに中止します。適切なNDEBUGの代わりにDEBUGを使用しますか?
スティーブジェソップ

lmao、もちろん、これをそれほど間違っているのはjava-samplesと呼ばれるWebサイトです。
underscore_d

6

assert()関数はプログラムのバグを診断できます。Cではで定義され<assert.h>、C ++ではで定義され<cassert>ます。そのプロトタイプは

void assert(int expression);

引数式は、テストしたい任意のもの(変数または任意のC式)にすることができます。式がTRUEと評価された場合、assert()は何もしません。式の評価がFALSEの場合、assert()はstderrにエラーメッセージを表示し、プログラムの実行を中止します。

assert()をどのように使用しますか?これは、プログラムのバグ(コンパイルエラーとは異なる)を追跡するために最も頻繁に使用されます。バグによってプログラムのコンパイルが妨げられることはありませんが、不正な結果が返されたり、不適切に実行される(たとえば、ロックアップする)ことがあります。たとえば、作成している財務分析プログラムが誤った答えを出すことがあります。この問題は、変数interest_rateが負の値を取ることが原因であると思われますが、これは決して起こらないはずです。これを確認するには、ステートメントを配置します

assert(interest_rate> = 0); Interest_rateが使用されるプログラム内の場所。変数が負になる場合は、assert()マクロが警告します。次に、関連するコードを調べて、問題の原因を特定できます。

assert()の動作を確認するには、以下のサンプルプログラムを実行してください。ゼロ以外の値を入力すると、プログラムは値を表示し、正常に終了します。ゼロを入力すると、assert()マクロはプログラムの異常終了を強制します。表示される正確なエラーメッセージはコンパイラによって異なりますが、典型的な例を次に示します。

アサーションが失敗しました:x、ファイルlist19_3.c、13行目assert()が機能するためには、プログラムがデバッグモードでコンパイルされている必要があります。デバッグモードを有効にする方法については、コンパイラのドキュメントを参照してください(すぐに説明します)。後でリリースモードで最終バージョンをコンパイルすると、assert()マクロは無効になります。

 int x;

 printf("\nEnter an integer value: ");
 scanf("%d", &x);

 assert(x >= 0);

 printf("You entered %d.\n", x);
 return(0);

整数値を入力してください:10

10を入力しました。

整数値を入力してください:-1

エラーメッセージ:プログラムの異常終了

エラーメッセージは、システムとコンパイラによって異なりますが、一般的な考え方は同じです。


サンプルプログラムがアサートでどのように機能するかを説明しました。アサート自体がどのように機能するかではありません。どのようにしてプログラムを異常終了させますか?それはある種の例外を投げますか?何?特別な信号を作成しますか?どの信号?アサーションは、あらゆる種類のC ++ try-catchメカニズムによって「キャッチ」できますか?
Motti Shneor 2016

4

「例外を発生させる」や「実行を停止する」などのことは、ほとんどのコンパイラでは当てはまるかもしれませんが、すべてでは当てはまりません。(ところで、本当に例外をスローするassertステートメントはありますか?)

これは、c6xと他のTIコンパイラが使用するアサートの興味深い、わずかに異なる意味です。特定のアサートステートメントを確認すると、これらのコンパイラはそのステートメントの情報を使用して特定の最適化を実行します。邪悪な。

Cの例:

int dot_product(short *x, short *y, short z)
{
  int sum = 0
  int i;

  assert( ( (int)(x) & 0x3 ) == 0 );
  assert( ( (int)(y) & 0x3 ) == 0 );

  for( i = 0 ; i < z ; ++i )
    sum += x[ i ] * y[ i ];
  return sum;
}

これは、配列が32ビット境界で整列されていることをコンパイラーに伝えます。そのため、コンパイラーは、そのような整列のために作成された特定の命令を生成できます。


1
それで、アサートがfalseでNDEBUGが設定されていない場合、彼らは何をしますか?これが<assert.h>からのアサートのバージョンである場合、標準はメッセージを出力して中止することを要求しています。明らかに、規格はステートメントの真実に基づいて最適化することが許可されていないことを述べていませんが、準拠するためには、それがfalseの場合は中止する必要があります。
スティーブジェソップ

1
標準的な動作に従います
2009年

1

C ++ 11 N3337標準ドラフト

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf

19.3アサーション

1(表42)で説明されているヘッダー<cassert>は、C ++プログラムのアサーションを文書化するマクロと、アサーションチェックを無効にするメカニズムを提供します。

2内容は、標準Cライブラリヘッダー<assert.h>と同じです。

C99 N1256標準ドラフト

http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

7.2診断<assert.h>

1ヘッダー<assert.h>はアサートマクロをNDEBUG定義し、で定義されていない別のマクロを参照してい<assert.h>ます。NDEBUG<assert.h>がインクルードされているソースファイルのポイントでマクロ名として定義されている場合、assertマクロは次のように定義されます。

 #define assert(ignore) ((void)0)

アサートマクロは、NDEBUG <assert.h>が含まれるたびに、NDEBUGの現在の状態に従って再定義さ れます。

2. assertマクロは、実際の関数としてではなく、マクロとして実装されます。実際の関数にアクセスするためにマクロ定義が抑制されている場合、動作は未定義です。

7.2.1プログラム診断

7.2.1.1アサートマクロ

あらすじ

1。

#include <assert.h>
void assert(scalar expression);

説明

2 assertマクロは診断テストをプログラムに入れます。void式に展開されます。これが実行されると、式(スカラー型を持つ必要があります)がfalse(つまり、0に等しい)の場合、assertマクロは失敗した特定の呼び出しに関する情報(引数のテキスト、後者は、それぞれ前処理マクロの値である-ソースファイル、ソース行番号、及び封入機能の名前__FILE__及び__LINE__識別子の __func__実装で定義されたフォーマットで標準エラーストリームに)。165)次に、アボート関数を呼び出します。

戻り値

3 assertマクロは値を返しません。


1

else ifとprintfが通常よりもassert()関数を使用する主な理由は3つあります。

  1. assert()関数は主にデバッグ段階で使用されますが、最終的なコードでうまく行かない可能性がある条件をテストするたびに、printfステートメントを使用して書き込むのは面倒です。

  2. 大規模なソフトウェア展開では、assertが非常に便利です。assert()関数のヘッダーファイルをリンクする前に定義されたNDEBUGマクロを使用して、コンパイラーにassert文を無視させることができます。

  3. assert()は、関数またはコードを設計していて、コードが機能して何が機能しないのかを知りたい場合や、基本的に仮定で遊んでいると評価するためのif elseを最後に含めたい場合に便利です。


0

評価した値が偽の場合、プログラムの実行を停止する関数です。通常、マクロで囲まれているため、リリース設定でコンパイルした場合、結果のバイナリにコンパイルされません。

それはあなたがした仮定をテストするために使用するように設計されています。例えば:

void strcpy(char* dest, char* src){
    //pointers shouldn't be null
    assert(dest!=null);
    assert(src!=null);

    //copy string
    while(*dest++ = *src++);
}

必要な理想は、無効な引数を使用して関数を呼び出すなど、プログラムでエラーを発生させ、segfaultする前にアサートをヒットする(または期待どおりに機能しない)ことです。


if&elseだけを使用して、ログ情報を追加しないのはなぜですか?
アサドカーン

1
なぜなら、strcpyにnullポインターを渡してはならないからです。それは起こってはならないことの一つです。nullポインタが渡された場合、それはより高いレベルの何かが台無しになっていることを示します。せいぜい、予期しないデータ値(destが正しくないか、nullであるため)のために、問題からさらにプログラムをクラッシュさせなければならないことになります。
Yacoby、2009年

-5

さらに、これを使用して、動的割り当てが成功したかどうかを確認できます。

コード例:

int ** p;
p = new int * [5];      // Dynamic array (size 5) of pointers to int
for (int i = 0; i < 5; ++i) {
    p[i] = new int[3]; // Each i(ptr) is now pointing to a dynamic
                       // array (size 3) of actual int values
}

assert (p);            // Check the dynamic allocation.

に似ている:

if (p == NULL) {
    cout << "dynamic allocation failed" << endl;
    exit(1);
}

3
いいえ、newあなたが指定しない限り、割り当ての失敗の例外がスローされますnothrow(あなたがここでありませんでした)。さらに、あなたのフォーマットは奇妙でexit悪です。
オービットのライトネスレース

はい、あなたは正しいです。追加しないのを忘れました。出口の代わりにどのように使用するかを見たい
Sadikov

1
@Sadikov他の誰もが、リリースモードビルドするときに完全に削除されないコードを使用してこのようなエラー状態を処理します。これにより、前提条件が満たされていない場合、ユーザーは保護されず、未定義の動作に翻弄されます。これにより、決してチェックしてキャッチされません。リリースビルドが作成されるずっと前にassert()決して決して決して、発生してはならないことをデバッグしてスタンプするためのものです。
underscore_d
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.