Caution
お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。
assert() / static_assert
プログラムの前提条件が満たされているかを実行時に検証するマクロです。『<assert.h>』に定義されており、条件が偽のときにプログラムを強制終了してデバッグ情報を出力します。C11からは静的解析用の『static_assert』も使えます。
構文
// 実行時アサーション。条件が偽のとき、ファイル名・行番号・条件式を出力して abort() します。 // NDEBUG が定義されている場合、このマクロは何もしない空の式に展開されます(本番用)。 void assert(scalar expression); // コンパイル時アサーション(C11以降)。条件が偽のときにコンパイルエラーになります。 // message は文字列リテラルで、エラーメッセージとして表示されます。 static_assert(constant-expression, message); // _Static_assert とも書けます(C11の正式キーワード)。
NDEBUG による切り替え
| 状態 | assert() の動作 |
|---|---|
| NDEBUG 未定義(デフォルト) | 条件が偽のとき abort() で強制終了し、ファイル名・行番号・条件式を出力します。 |
| NDEBUG 定義済み(本番ビルド) | assert() は何もしない空の式に展開されます。実行時コストがゼロになります。 |
サンプルコード
#include <stdio.h>
#include <assert.h>
#include <stdint.h> // static_assert で使います。
// static_assert でコンパイル時の型サイズを検証します(C11以降)。
static_assert(sizeof(int) >= 4, "int は 4 バイト以上が必要です");
// 配列のインデックスが有効範囲かチェックする関数です。
int get_element(int *arr, int size, int index) {
assert(arr != NULL); // 配列ポインタが NULL でないことを確認します。
assert(size > 0); // サイズが正であることを確認します。
assert(index >= 0); // インデックスが 0 以上であることを確認します。
assert(index < size); // インデックスが範囲内であることを確認します。
return arr[index];
}
// 割り算でゼロ除算を防ぐ例です。
double safe_divide(double a, double b) {
assert(b != 0.0); // 除数がゼロでないことを確認します。
return a / b;
}
int main(void) {
int nums[] = {10, 20, 30, 40, 50};
// 正常なケース(アサーションはすべて通過します)。
printf("nums[2] = %d\n", get_element(nums, 5, 2)); // 『30』と出力されます。
printf("10 / 4 = %.2f\n", safe_divide(10.0, 4.0)); // 『2.50』と出力されます。
// 以下のコメントを外すとアサーション失敗でプログラムが終了します。
// get_element(nums, 5, 10); // index 10 は範囲外(assert 失敗)。
// safe_divide(5.0, 0.0); // ゼロ除算(assert 失敗)。
printf("すべてのチェックを通過しました。\n");
return 0;
}
概要
『assert()』はバグの早期発見に非常に有効な手段です。「この地点でこの値は必ず正のはずだ」「このポインタは NULL になりえないはずだ」という前提条件を明示的にコードで表現できます。アサーションが失敗すると、ファイル名と行番号が出力されるためバグの特定が容易になります。
本番ビルドでは『NDEBUG』マクロを定義することで、assert() の呼び出しをすべて無効化できます。GCC や Clang では『-DNDEBUG』オプションで定義できます。これにより、デバッグビルドと本番ビルドでコードを変更することなく切り替えられます。
assert() の中に副作用のある式を書かないでください。NDEBUG が定義されると assert() の中身が消えるため、副作用(関数呼び出し・変数の更新など)も消えてしまい、デバッグビルドと本番ビルドで動作が変わります。
『static_assert()』(C11以降)はコンパイル時に評価されるため、型のサイズやアライメントなどコンパイル時に確認できる条件に使います。実行時には何のコストも発生しません。C11 より前の環境では使用できません。
デバッグ関連では『プリプロセッサディレクティブ(#pragma / #error)』も参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。