头文件<assert.h>唯一的目的就是提供宏assert的定义。可以在程序中关键的地方使用这个宏来进行断言。如果一处断言被证明非真,程序将在标准错误流输出一条适当的提示信息,并且执行异常终止。可以通过宏NDEBUG在改变assert的展开方式。如果程序中某个包含<assert.h>的地方没有定义NDEBUG,该文件将会将宏assert定义为活动形式,反之,如果定义了NDEBUG,头文件将会把这个宏定义为不执行任何操作的静止形式。
由上,在每次包含<assert.h>时,assert宏的行为由是否定义NDEBUG决定,此头文件不具备幂等性(即一次包含和多次包含的行为可能不一样)。
assert.h的简单实现:
assert.h
#undef assert
#ifndef NDEBUG
#define assert(test) ((void)0)
#else
void _Assert(char *);
#define _STR(x) _VAL(x)
#define _VAL(x) #x
#define assert(test) ((test) ? (void)0 : _Assert(__FILE__":"_STR(__LINE__)""#test"))
assert.c
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
void _Assert(char *mesg)
{
fputs(mesg, stderr);
fputs("-- assertion failed\n", stderr);
abort(); // 调用abort,它产生SIGABRT信号。默认的SIGABRT信号处理函数将终止程序
}
assert测试文件:
tassert.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
static int val = 0;
static void field_abort(int sig)
{
if(val == 1)
{
puts("SUCCESS testing <assert.h>");
exit(EXIT_SUCCESS);
}
else
{
puts("FAILURE testing <assert.h>");
exit(EXIT_FAILURE);
}
}
#define NDEBUG
#include <assert.h>
static void dummy(void)
{
int i = 0;
assert(i == 0);
assert(i == 1);
}
#undef NDEBUG
#include <assert.h>
int main(void)
{
assert(signal(SIGABRT, &field_abort) != SIG_ERR);
dummy();
assert(val == 0);
++val;
fputs("Sample assertion failure message --\n", stderr);
assert(val == 0);
puts("FAILURE testing <assert.h>");
return(EXIT_FAILURE);
}
测试结果:
Sample assertion failure message --
tassert: tassert.c:41: main: Assertion `val == 0' failed.
SUCCESS testing <assert.h>