これが私がこれを行う方法です。コードの下の議論。
一部の .h ファイルでは:
#define PASS ((void)0)
extern void hook(void);
extern void asserthook(void);
#ifdef DEBUG
#define ENABLE_ASSERTS
#endif // DEBUG
#ifdef ENABLE_ASSERTS
#define AssertMesg(expr, mesg) \
do { \
if (!(expr)) \
{ \
asserthook(); \
fprintf(streamErr, \
"%s(%d): assertion failed: ", __FILE__, __LINE__); \
fprintf(streamErr, "%s\n", mesg); \
fflush(streamErr); \
Exit(10); \
} \
} while (0)
#define Assert(expr) AssertMesg(expr, "")
#else // !ENABLE_ASSERTS
#define AssertMesg(expr, mesg) PASS
#define Assert(expr) PASS
#endif // !ENABLE_ASSERTS
そして、いくつかの .c ファイルで:
void hook(void)
{
PASS;
}
void asserthook(void)
{
hook();
}
まず第一に、私のアサートは常にasserthook()
which calls を呼び出しますhook()
。これらの関数は、ブレークポイントを設定する場所にすぎません。errhook()
エラーのために呼び出されることもあります。通常、hook()
自分自身にブレークポイントを設定するだけで、アサートによってコードがダウンするたびに、必要な場所でスタック バックトレースを使用して、デバッガーをエラーで停止させます。
C ステートメントのように動作する複数行のマクロを作成しようとする場合、通常はマクロを中かっこで囲み、それらの中かっこをdo
/で囲みますwhile (0)
。これは 1 回実行するループなので、実際にはループではありません。しかし、そのようにラップするということは、それがステートメントであることを意味し、行にセミコロンを置いてステートメントを終了させると、実際には正しいことになります。したがって、このようなコードはエラーなしでコンパイルされ、正しいことを行います。
if (error)
AssertMesg(0, "we have an error here");
else
printf("We don't have an error after all.\n");
do
ばかげた/ラッパーを実行せずwhile (0)
、中括弧だけを使用した場合、上記のコードは機能しません! まず、コンパイラは、なぜ;
中括弧の後とelse
;の前に右があるのか疑問に思うでしょう。2 番目に、はマクロ内else
の非表示の に関連付けられ、は決して呼び出されません。明示的な中括弧を使用して後者の問題を修正できますが、すべての状況で機能するようにマクロを設定する方が明らかに優れており、それが/の役割です。if
AssertMesg()
printf()
do
while (0)
(void)0
私の好みの何もしないステートメントです。必要に応じて使用do {} while (0)
することも、副作用がなく、変数を使用しないものを使用することもできます。
do
/トリックの最悪の点while (0)
は、ループについて不平を言うエラー メッセージが時々表示されることですdo
。これはマクロ内に隠されているため、実際に何が起こっているのかを覚えておく必要があります。しかし、複数行のマクロを正しく動作させるには、これが私が知っている最善の方法です。
可能であれば、マクロではなく静的インライン関数を使用する必要があります。しかし、マクロは下手な C コンパイラにも完全に移植可能であり、適切__FILE__
に展開できるようにアサートにマクロを使用する必要があります。__LINE__
(実際のアサートを行う varargs 関数を作成してから、使用するすべてのコンパイラで varargs が正しく機能する限り、その関数への単一の呼び出しに展開されるマクロを作成することができます。私は今それを行うことができると思います,しかし、私はすでに複数行のマクロソリューションを機能させており、長い間それに触れていません.)