为什么断言宏,而不是一个功能? [英] Why is assert a macro and not a function?

查看:202
本文介绍了为什么断言宏,而不是一个功能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的讲师已要求我,在类,我想知道为什么它是一个宏观的,而不是一个功能?


解决方案

简单的解释是,该标准要求断言是一个宏,如果我们看一下 C99标准草稿据我可以告诉节是C11 标准草案相同以及的)第 7.2 诊断的段落的 2 的说道:


  

断言宏应执行一个宏,而不是作为一个实际的
  功能。如果宏定义燮pressed才能访问
  实际功能,其行为是不确定的。


为什么它要求这一点,在给出的理由对国际准则的理由编程语言-C 是:


  

有可能很难或不可能使断言一个真正的功能,因此,它被限制为宏
  形式。


这是不是非常丰富,但是我们可以从其他要求见的原因。让我们回到第 7.2 段的 1 的说道:


  

[...]如果NDEBUG是在源文件中的点定义为宏名
  包括在哪里,断言宏被简单地定义为

 的#define断言(忽略)((无效)0)


  
  

断言宏根据NDEBUG的当前状态重新定义
  每个所包含的时间。


这是重要的,因为它允许我们一个简单的方法来关闭在释放模式断言,你可能要采取潜在的昂贵的检查费用。

和第二个重要的要求是,它是需要使用宏 __ FILE __ __ LINE __ __ FUNC __ ,这是覆盖在部分 7.2.1.1 的断言宏的它说:


  

[...] assert宏写关于特定呼叫的信息
  失败[...]后者的分别的值
  preprocessing宏__FILE_ _和__LINE_ _标识符和
  __func_ _)在一个实现定义的格式标准错误流。 165)然后调用abort函数。


在这里脚注 165 说:


  

写入的消息可能是下面的形式:

 断言失败:前pression,功能ABC,XYZ文件,行NNN。


有它作为一个宏允许宏 __ FILE __ 等等......在适当的位置进行评估和约阿希姆指出是宏允许它插入原始的前pression 的它生成的消息。

草案C ++标准要求了cassert 标题的内容都是一样的 ASSERT.H 头从STANDRD C库:


  

的内容是一样的标准C库头。


  
  

    

另请参阅:ISO C 7.2


  

为什么(无效)0?

为什么要用(无效)0 相对一些其他前pression,做什么?我们可以想出几个原因,首先,这是断言简介的外观在第 7.2.1.1

 无效断言(标量前pression);

和它说(的重点煤矿的):


  

断言宏把诊断测试进入程序;它的扩展到一个空白的前pression。


恩pression (无效)0 是需要用的无效前pression落得一致的。

假设我们没有这个要求,其他可能的前pressions可能有不良的影响,如允许,将不会被允许在释放模式的使用断言使用普通调试模式,例如 0 将使我们能够在分配中使用断言和正确的使用可能会产生一个前pression结果未用时警告。作为使用的复合语句的一个意见建议,我们可以从Ç多行宏见:DO /而(0)与范围块的,它们一个在某些情况下,不希望的效果。

My lecturer has asked me that in class, and I was wondering why is it a macro instead of a function?

解决方案

The simple explanation would be that the standard requires assert to be a macro, if we look at the draft C99 standard(as far as I can tell the sections are the same in draft C11 standard as well) section 7.2 Diagnostics paragraph 2 says:

The assert macro shall be implemented as a macro, not as an actual function. If the macro definition is suppressed in order to access an actual function, the behavior is undefined.

Why does it require this, the rationale given in Rationale for International Standard—Programming Languages—C is:

It can be difficult or impossible to make assert a true function, so it is restricted to macro form.

which is not very informative, but we can see from other requirements why. Going back to section 7.2 paragraph 1 says:

[...]If NDEBUG is defined as a macro name at the point in the source file where is included, the assert macro is defined simply as

#define assert(ignore) ((void)0)

The assert macro is redefined according to the current state of NDEBUG each time that is included.

This is important since it allows us an easy way to turn off assertions in release mode where you may want to take the cost of potentially expensive checks.

and the second important requirement is that it is required to use the macros __FILE__, __LINE__ and __func__, which is covered in section 7.2.1.1 The assert macro which says:

[...] the assert macro writes information about the particular call that failed [...] the latter are respectively the values of the preprocessing macros __FILE_ _ and __LINE_ _ and of the identifier __func_ _) on the standard error stream in an implementation-defined format.165) It then calls the abort function.

where footnote 165 says:

The message written might be of the form:

Assertion failed: expression, function abc, file xyz, line nnn.

Having it as a macro allows the macros __FILE__ etc... to be evaluated in the proper location and as Joachim points out being a macro allows it to insert the original expression in the message it generates.

The draft C++ standard requires that the contents of the cassert header are the same as the assert.h header from Standrd C library:

The contents are the same as the Standard C library header .

See also: ISO C 7.2.

Why (void)0?

Why use (void)0 as opposed to some other expression that does nothing? We can come up with a few reasons, first this is how the assert synopsis looks in section 7.2.1.1:

void assert(scalar expression);

and it says (emphasis mine):

The assert macro puts diagnostic tests into programs; it expands to a void expression.

the expression (void)0 is consistent with the need to end up with a void expression.

Assuming we did not have that requirement, other possible expressions could have undesirable effects such as allowing uses of assert in release mode that would not be allowed in debug mode for example using plain 0 would allow us to use assert in an assignment and when used correctly would likely generate an expression result unused warning. As for using a compound statement as a comment suggests, we can see from C multi-line macro: do/while(0) vs scope block that they an have undesirable effects in some cases.

这篇关于为什么断言宏,而不是一个功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆