C Language
アサーション
サーチ…
前書き
アサーションは、アサーションにソフトウェアが遭遇した瞬間に、提示された条件が真でなければならないという述語です。最も一般的なのは、実行時に検証される単純なアサーションです。ただし、 静的アサーションはコンパイル時にチェックされます。
構文
- アサート(式)
- static_assert(式、メッセージ)
- _Static_assert(式、メッセージ)
パラメーター
パラメータ | 詳細 |
---|---|
表現 | スカラー型の表現。 |
メッセージ | 診断メッセージに含める文字列リテラル。 |
備考
assert
とstatic_assert
はassert.h
定義されたマクロです。
assert
の定義は、標準ライブラリで定義されていないマクロNDEBUG
依存します。 NDEBUG
が定義されている場合、 assert
はノーオペレーションです:
#ifdef NDEBUG # define assert(condition) ((void) 0) #else # define assert(condition) /* implementation defined */ #endif
オピニオンは、 NDEBUG
を常にプロダクションのコンパイルに使用するかどうかによって異なります。
- プロのキャンプは、と主張している
assert
呼び出しがabort
と結果がユーザにとって有益ではないので、アサーションメッセージは、エンドユーザーにとって便利ではありません。本番コードでチェックする致命的な条件を持っている場合は、通常使用する必要がありますif/else
の条件及びexit
またはquick_exit
プログラムを終了します。abort
とは対照的に、これらはプログラムが(atexit
またはat_quick_exit
登録された関数を介して)何らかのクリーンアップを行うことを可能にします。 - コンキャンプは、
assert
コールはプロダクションコードでは決して発射すべきではないとassert
ますが、もしそうであれば、チェックされる条件は何か劇的に間違っていることを意味し、実行が続行されると悪化します。したがって、アサーションをプロダクションコードでアクティブにする方が良いです。なぜなら、それらが起動すると、地獄はすでに緩んでいるからです。 - もう1つの選択肢は、チェックを常に実行するアサーションの自家製システムを使用し、開発(
abort
が適切な場合)と生産(「予期しない内部エラー - テクニカルサポートに連絡してください」が適切かもしれない場合)の違いを処理することです。
static_assert
はキーワードである_Static_assert
展開されます。条件はコンパイル時にチェックされるため、 condition
は定数式でなければなりません。これを開発と生産の間で別々に扱う必要はありません。
前提条件と事後条件
アサーションのユースケースの1つは、前提条件と事後条件です。これは、契約によって 不変および設計を維持するために非常に有用であり得る。例として、長さは常にゼロまたは正であるため、この関数はゼロまたは正の値を返す必要があります。
#include <stdio.h>
/* Uncomment to disable `assert()` */
/* #define NDEBUG */
#include <assert.h>
int length2 (int *a, int count)
{
int i, result = 0;
/* Precondition: */
/* NULL is an invalid vector */
assert (a != NULL);
/* Number of dimensions can not be negative.*/
assert (count >= 0);
/* Calculation */
for (i = 0; i < count; ++i)
{
result = result + (a[i] * a[i]);
}
/* Postcondition: */
/* Resulting length can not be negative. */
assert (result >= 0);
return result;
}
#define COUNT 3
int main (void)
{
int a[COUNT] = {1, 2, 3};
int *b = NULL;
int r;
r = length2 (a, COUNT);
printf ("r = %i\n", r);
r = length2 (b, COUNT);
printf ("r = %i\n", r);
return 0;
}
単純アサーション
アサーションは、そのコード行に到達したときにファクトが真でなければならないと主張するために使用されるステートメントです。アサーションは、期待される条件が満たされることを保証するのに役立ちます。アサーションに渡された条件が真の場合、アクションはありません。 false条件の動作は、コンパイラフラグによって異なります。アサーションが有効になっていると、誤った入力が発生するとすぐにプログラムが停止します。それらが無効になっているときは何もしません。アサーションは、リリースではしばしば有効になっていますが、内部ビルドやデバッグビルドでアサーションを有効にし、リリースビルドでアサーションを無効にするのが一般的です。 (終了がエラーよりも良いか悪いかは、プログラムによって異なります。)アサーションは、内部プログラミングエラーを捕捉するためにのみ使用してください。通常、悪いパラメータが渡されます。
#include <stdio.h>
/* Uncomment to disable `assert()` */
/* #define NDEBUG */
#include <assert.h>
int main(void)
{
int x = -1;
assert(x >= 0);
printf("x = %d\n", x);
return 0;
}
NDEBUG
出力は未定義です:
a.out: main.c:9: main: Assertion `x >= 0' failed.
NDEBUG
可能な出力の定義:
x = -1
すべてのアサーションをオンまたはオフにしてコードを簡単にコンパイルできるように、 NDEBUG
グローバルに定義することをお勧めします。これを行う簡単な方法は、 NDEBUG
をコンパイラのオプションとして定義するか、共有構成ヘッダー( config.h
)で定義することです。
静的アサーション
静的アサーションは、コードのコンパイル時に条件が真であるかどうかをチェックするために使用されます。そうでない場合、コンパイラはエラーメッセージを発行し、コンパイルプロセスを停止する必要があります。
静的アサーションは、実行時ではなくコンパイル時にチェックされるアサーションです。条件は定数式でなければならず、falseの場合はコンパイラエラーが発生します。チェックされる最初の引数は定数式で、2番目の引数は文字列リテラルでなければなりません。
assertとは異なり、 _Static_assert
はキーワードです。便利なマクロstatic_assert
は、 <assert.h>
定義されています。
#include <assert.h>
enum {N = 5};
_Static_assert(N == 5, "N does not equal 5");
static_assert(N > 10, "N is not greater than 10"); /* compiler error */
C11以前は、静的アサーションの直接サポートはありませんでした。ただし、C99では、コンパイル時の条件がfalseの場合にコンパイルエラーを引き起こすマクロで静的なアサーションをエミュレートできます。 _Static_assert
とは異なり、2番目のパラメータは適切なトークン名である必要があり、そのため変数名を使用して変数名を作成できます。アサーションに失敗した場合、その変数は構文的に不正な配列宣言で使用されていたため、コンパイラエラーに変数名が見られます。
#define STATIC_MSG(msg, l) STATIC_MSG2(msg, l)
#define STATIC_MSG2(msg,l) on_line_##l##__##msg
#define STATIC_ASSERT(x, msg) extern char STATIC_MSG(msg, __LINE__) [(x)?1:-1]
enum { N = 5 };
STATIC_ASSERT(N == 5, N_must_equal_5);
STATIC_ASSERT(N > 5, N_must_be_greater_than_5); /* compile error */
C99以前では、ブロック内の任意の場所に変数を宣言することができなかったので、このマクロの使用については非常に慎重でなければなりません。
到達不可能なコードのアサーション
開発中に、特定のコードパスが制御フローの到達を妨げる必要があるときは、 assert(0)
を使用assert(0)
て、そのような条件が誤っていることを示すことができます。
switch (color) {
case COLOR_RED:
case COLOR_GREEN:
case COLOR_BLUE:
break;
default:
assert(0);
}
assert()
マクロの引数がfalseを評価assert()
たびに、マクロは診断情報を標準エラーストリームに書き込み、プログラムを中止します。この情報には、 assert()
ステートメントのファイルと行番号が含まれており、デバッグに非常に役立ちます。 NDEBUG
は、マクロNDEBUG
定義することによって無効にすることができます。
エラーが発生したときにプログラムを終了させるもう1つの方法は、標準ライブラリ関数exit
、 quick_exit
またはabort
です。 exit
とquick_exit
はあなたの環境に戻すことができる引数をとります。 abort()
(したがってassert
)はプログラムの重大な終了となり、実行終了時に実行されるクリーンアップは実行されません。
assert()
の主な利点は、デバッグ情報を自動的に出力することです。 abort()
を呼び出すと、 abort()
ように無効にすることはできませんが、デバッグ情報が表示されないことがあります。いくつかの状況では、両方のコンストラクトを併用すると効果的です。
if (color == COLOR_RED || color == COLOR_GREEN) {
...
} else if (color == COLOR_BLUE) {
...
} else {
assert(0), abort();
}
アサートが有効になると、 assert()
コールはデバッグ情報を出力し、プログラムを終了します。実行は決してabort()
呼び出しに達しません。アサーションが無効になると、 assert()
コールは何もせず、 abort()
が呼び出されます。これにより、プログラムは常にこのエラー状態で終了します。アサートの有効化と無効化は、デバッグ出力が出力されるかどうかにかかわらず影響を与えます。
あなたは、このようなままにすることはありませんassert
デバッグ情報は、エンドユーザーにとって有益ではないためとするので、生産コード内をabort
一般的にインストールされているクリーンアップハンドラ阻害あまりにもひどい終了でexit
またはquick_exit
実行することを。
アサートエラーメッセージ
アサーションとともにエラーメッセージを表示できるトリックが存在します。通常、次のようなコードを記述します
void f(void *p)
{
assert(p != NULL);
/* more code */
}
アサーションが失敗した場合は、エラーメッセージが似ています
アサーションが失敗しました:p!= NULL、ファイルmain.c、行5
ただし、論理AND( &&
)を使用してエラーメッセージを表示することもできます
void f(void *p)
{
assert(p != NULL && "function f: p cannot be NULL");
/* more code */
}
今、アサーションが失敗した場合、エラーメッセージは次のようになります
アサーションが失敗しました:p!= NULL && "関数f:pはNULLにできません"、ファイルmain.c、行5
これがなぜ機能するかについての理由は、文字列リテラルが常に非ゼロ(true)と評価されるためです。ブール式に&& 1
を追加しても効果はありません。したがって、 && "error message"
追加しても、コンパイラは失敗した式全体を表示します。