用于宏重新定义的合法用例

时间:2017-02-10 19:20:30

标签: c c-preprocessor

阅读关于预处理器的章节,它指出只有重新定义符合先前的定义时才允许重新定义宏,即:

#define FOO 0
#define BAR 1+1
#define FOO 0     /* ok. */
#define BAR 1 + 1 /* not ok */ 

我对此感到困惑。

当然这种行为是正确的(当然这本书可能是错的),我的问题是:为什么要允许这个?我想不出任何可以使用它的合法用例(授予我没有经验),它背后是否有理性?

2 个答案:

答案 0 :(得分:2)

我们的想法是让预处理器主动观察重复的定义并确保它们保持一致。

Rationale to C99 standard

实际上提到了这条规则背后的基本原理
  

委员会希望不允许“恶毒的重新定义”,例如

     

(在header1.h中)

     

#define NBUFS 10

     

(在header2.h中)

     

#define NBUFS 12

     

这显然是对程序中严重错误的邀请。然而,仍然存在“良性重新定义”的问题,例如

     

(在header1.h中)

     

#define NULL_DEV / *第一次* / 0

     

(在header2.h中)

     

#define NULL_DEV / *第二次* / 0

     

C89委员会的结论是,通过允许在定义相同的情况下进行良性重新定义,可以更好地实现安全编程实践。这允许独立标题指定他们对每个感兴趣符号的正确值的理解,仅在定义不同时才生成诊断。

基本上,当两个定义存在且它们不同时,我们的想法是故意捕捉和暴露情境。如果用户在定义自己的定义之前总是被迫预测和#undef之前的定义,他们会悄悄地覆盖不打算覆盖的内容,而无法确保一致性。

通过故意提供额外相同的定义,您可以有效地引入额外的保护级别:如果某人修改了之前的定义,预处理器将立即捕获并报告由此产生的不匹配。

换句话说,通过定义

#define A 42

在您的代码中,您不仅要将A定义为42,还要告诉预处理器您要确保其他所有人(在此翻译单元中)共享同一个概念{ {1}}应该是。

答案 1 :(得分:1)

你的书是完全正确的,但也许没有指出 - 或者你可能忽略了它 - 您可以重新定义先前定义的预处理器,但不提供诊断 在重新定义它之前你取消它。 E.g:

#define FOO 0
#define BAR 1+1
#define FOO 0     /* ok. */
#undef BAR
#define BAR 1 + 1 /* ok */ 

如果您在 定义时尝试重新定义宏,则概率很高 你犯了一个大错,并且会对预处理器感激不尽 请你注意。

在文件中定义一个宏,这个宏驻留在一个大而复杂的文件中 产品代码库 - 可能具有多个交织在一起的构建配置 由最终在代码库外定义的宏控制, 在构建系统中 - 然后知道这可能超出你的独立智慧 你的定义永远不会,灾难性地与建立任何一个的先前定义相矛盾 组态。你想知道这一点,预处理器会告诉你。

另一方面,有些情况下你想说:FOO 可能或 可能没有从我的某个地方获得事先的定义 文件已编译。无论如何,我希望它现在有我的定义。 我知道我在做什么,而且在我的脑海中。预处理器可以让你想到这一点 责任如下:

<强> foo.c的

#include <bar.h>
...

#undef FOO // I don't care what it previously might have been.
#define FOO what I want here

并保持安静。

从这个角度来看,为什么预处理器抱怨的问题 可能是宏重新定义与最后一个没有区别 驱散。相同的重新定义是无害的。没用,是的,但不是 必然暗示或任何人都重复了自己。图书馆 标头文件libfoo.hlibbar.h可能都包含在baz.c和。{1}}中 他们每个人都可能包含。

#define MAX_HANDLES 255

预处理器将看到两次。但这是无害的,为什么要抱怨?