【问题标题】:C interfaces and implementations: why there are both function assert and macro assert?C 接口和实现:为什么同时存在函数断言和宏断言?
【发布时间】:2014-03-26 05:04:53
【问题描述】:

在“C接口和实现”4.3中,在assert.h中:

#undef assert
#ifdef NDEBUG
#define assert(e) ((void)0)
#else
#include "except.h"
extern void assert(int e);
#define assert(e) ((void)((e)||(RAISE(Assert_Failed), 0)))
#endif

extern void assert(int e); 的目的是什么?因为在assert.c中,它是由assert宏实现的。

【问题讨论】:

  • assert.c 和 except.h 中有什么?
  • void (assert)(int e) { assert(e); }
  • @self:问题很明确,他在问为什么assert 的宏和函数(其定义又是一个宏)都被定义了。
  • @brokenfoot 是的,我知道。所以?普通断言不需要两者。
  • 这样,如果你以后做#undef assert,你仍然可以assert(condition)。请注意,#undef assert 是未定义的行为,因此执行此操作是出于善意,而不是出于任何义务。

标签: c macros


【解决方案1】:

如果您仔细阅读本书的部分内容,您会发现它提供了assert() 的标准接口,但不提供符合标准的实现。

Assert 接口定义了标准指定的assert(e),除了断言失败引发异常Assert_Failed 而不是中止执行,并且不提供断言的文本e em>。

…从有问题的assert.h 中提取…

assert 模仿标准的定义,因此两个assert.h 标头可以互换使用,这就是Assert_Failed 出现在except.h 中的原因。这个接口的实现很简单:

assert.c

#include "assert.h"

const Except_T Assert_Failed = { "Assertion failed" };

void (assert)(int e) {
    assert(e);
}

你需要阅读本章的前面部分来了解异常处理机制和Except_T(和except.h)。

【讨论】:

  • 我们是否需要在 "assert.c" 中包含 "except.h" ?如果定义了NDEBUG,则“assert.h”中不包含“except.h”,因此“assert.c”中不包含“except.h”,因为Except_T不可见,所以会出现编译错误。
  • 我可能会争辩说assert.c 中的代码应该无条件地将#undef NDEBUG 放在顶部。编译断言处理的实现就好像永远不会启用断言一样是没有意义的。
【解决方案2】:

虽然看起来没有意义,但确实如此 - 至少在某些情况下。

assert()宏隐藏了标准定义,但仍有“后门”。

assert(1 == 0)

将调用宏,而您仍然可以通过

访问原始函数(如果已定义)
(assert)(1 == 0)

(括号禁止宏扩展)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-12
    • 2014-10-06
    • 1970-01-01
    • 2020-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-15
    相关资源
    最近更新 更多