【C言語】assertマクロ、NDEBUGマクロ|完全解説 & 活用テクニック

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の受け取りを拒否する
アサーション #バグや問題の根本原因を表明する
アサーション #バグの発生を事前に回避する

広告