为什么要断言一个macros而不是函数?
我的讲师在课堂上问我,我想知道为什么它是一个macros而不是一个function?
 简单的解释是,如果我们看看C99标准草案 ( 据我所知C11标准草案中的章节也是一样的),标准要求assert是一个macros。第7.2节诊断第2段说: 
断言macros应该被实现为一个macros而不是一个实际的函数。 如果为了访问一个实际的函数而禁止了macros定义,那么行为是不确定的。
为什么要这样做呢,国际标准程序devise语言C的理由是:
要确定一个真正的function是困难的或不可能的,所以它只限于macros观forms。
 这是不是很丰富,但我们可以从其他要求看到为什么。 回到第7.2节第1段说: 
[…]如果将NDEBUG定义为包含源文件中的macros名称,则assertmacros定义为
#define assert(ignore) ((void)0)每次包含时,根据NDEBUG的当前状态重新定义断言macros。
这很重要,因为它允许我们在发布模式中closures断言的简单方法,您可能想要花费昂贵的检查费用。
 第二个重要的要求是需要使用__func__ __FILE__ , __func__和__func__macros,这个在7.2.1.1节中讲述。 
[…] assertmacros在标准错误stream上写入有关特定调用失败的信息,后者分别是预处理macros__FILE_ _和__LINE_ _以及标识__func_ _)的值,实现定义的格式。 然后它调用中止函数。
 脚注165说: 
所写的信息可能是这样的forms:
Assertion failed: expression, function abc, file xyz, line nnn.
 把它作为一个macros允许macros__FILE__等…在正确的位置进行评估,因为Joachim指出macros是允许它在它生成的消息中插入原始expression式的。 
  C ++标准草案要求cassert头的内容与Standrd C库的assert.h头相同: 
内容与标准C库标题相同。
另见:ISO C 7.2。
为什么(无效)0?
 为什么使用(void)0而不是其他的expression方式? 我们可以想出几个理由,首先是7.2.1.1节中断言摘要的外观: 
 void assert(scalar expression); 
它说( 强调我的 ):
断言macros将诊断testing放入程序中; 它扩大到一个空洞的expression。
 expression式(void)0与需要以voidexpression式结束的expression式一致 。 
 假设我们没有这个要求,其他可能的expression式可能会产生不良影响,例如允许在debugging模式下不允许使用assert模式的assert ,例如使用普通的0将允许我们在一个赋值中使用assert ,以及正确使用可能会产生一个expression result unused警告。 至于使用复合语句作为注释build议,我们可以从C多行macros看到:do / while(0)vs scope block在某些情况下它们有不良效果。 
-  它允许捕获文件(通过__FILE__)和行号(通过__LINE__)
-  它允许assert替代一个有效的expression式,在释放模式下构build时什么也不做(即((void)0))
如果在包含macros名称NDEBUG时已经定义了该macros,则禁用该macros。 这允许编码器在debugging程序时根据需要在源代码中包含尽可能多的断言调用,然后通过简单地包括如下行来禁用所有这些调用程序:
 #define NDEBUG 
 在其代码的开头,包含<assert.h> 。 
因此,该macros被devise用来捕获编程错误,而不是用户或运行时错误,因为在程序退出debugging阶段后通常会被禁用。
把它作为函数会增加一些函数调用,并且你不能在释放模式下控制所有的这些断言。
 如果你使用函数,那么_FILE__ , _FILE__和__func__将给出这个断言函数代码的值。 不是说呼叫线路或呼叫function的线路。 
一些断言可能会很昂贵。 您刚刚编写了一个高性能的matrix求逆程序,并添加了一个完整性检查
 assert(is_identity(matrix * inverse)) 
 到最后。 那么,你的matrix是相当大的,如果assert是一个函数,那么在将它传递给assert之前,需要花费很多时间来进行计算。 如果你没有进行debugging,你真的不想花费时间。 
或者,也许断言是相对便宜,但它包含在一个非常短的函数,将被调用在内部循环。 或者其他类似的情况。
 通过assert一个macros来代替,当断言被closures时,你可以完全消除这个计算。 
为什么要断言一个macros而不是函数?
因为它应该以DEBUG模式编译,不应该以RELEASE模式编译。