assertマクロ
assertマクロは、与えられた条件式が偽(0と等しい)となる場合に診断メッセージを表示する機能です。その際には、不正な条件処理が発生した箇所の行番号や関数名、ファイル名、条件式の処理内容等が標準エラー出力に書き出されます。その後、assertマクロはabort関数を呼び出し、プログラムの異常終了を引き起こします。
// #include <assert.h>
assert(1 == 2); // 失敗: Assertion failed: (1 == 2), function main, file main.c, line 2.
assert(1 == 1); // 成功
条件式の評価結果が真(0以外の値)となる場合には何も行われません。なお、assertマクロによる診断はNDEBUGマクロが未定義の場合にのみ機能します。またassertマクロの呼び出しは常にvoid式として評価されます。
assertマクロの具体的な目的や活用方法については、アサーションに関する説明が参考になります。
アサーションとは|アサート機能の目的と活用例
目次
NDEBUGマクロ
NDEBUGはassertマクロを無効化するためのマクロです。NDEBUGマクロが定義された場合、assertマクロはvoid式(((void)0)
)として定義されます。また、assertマクロの引数に与えられた式は評価されなくなります。そのため、assertマクロの引数には副作用のある式を記述するべきではありません。
/* assert.h の実装イメージ */
#ifdef NDEBUG
// NDEBUGが定義されていた場合
#define assert(expr) ((void)0)
#else
// NDEBUGが未定義の場合
#define assert(expr) ((expr) ? ((void)0) : (void)(__assert(#expr, __FILE__, __LINE__)))
#define __assert(e, f, n) fprintf(stderr, "failed assertion `%s` %u:%s\n", e, n, f), abort()
#endif
コンパイラ側の-D
オプションを用いて、NDEBUGマクロを手動で定義することができます。
clang -DNDEBUG main.c
IDE(統合開発環境)によっては、リリースビルド時に自動的にNDEBUGが定義されるものもあります。XcodeではRelease時、Archive時、共にデフォルトではNDEBUGが定義されません(Xcode 7)。
プログラム側でNDEBUG
マクロを定義することも可能です。その場合はassert.h
ヘッダファイルのインクルード前に定義する必要があります。
#define NDEBUG
#include <assert.h>
int main() {
assert(1 == 2); // 非活性
}
void式として評価される
assertは基本的に、有効時/無効時、共にvoid式として評価されるため、assertをvoid型の戻り値や、カンマ演算子の途中式として利用することもできます。
// #define assert(expr) ((void)0)
void f(void *p) { return assert(p); }
int p(const char *s) { return assert(s), puts(s); }
このような活用はあまり一般的ではありませんが、マクロ作成時やショートコーディング活用時の際の有効なテクニックとなり得ます。
assertマクロの活用テクニック
assertマクロに独自のメッセージを表記するテクニックです。&&
演算子の短絡評価の特性や、文字列リテラルが真として評価される特性を活用しています。
assert(1 == 2 && "1 is not equal 2");
assert("fallen" && 1 == 2);
assert(!"go to bed");
以下は条件式の結果に応じて、エラーメッセージの出力とプログラムの停止を引き起こさせるテクニックです。ある種のブレークポイントのようなものとしても機能します。
if (1 != 2) {
assert(!"1 doesn't equal 2");
} else {
/* do something */
}
先程紹介した「# void式として評価される」のテクニックも参考になります。
assertマクロの活用方法
assertマクロの活用方法については、アサーションのページを参考にしてください。
アサーション #nullの受け取りを拒否する
アサーション #バグや問題の根本原因を表明する
アサーション #バグの発生を事前に回避する