【问题标题】:Will ifndef always work on an object-like macro defined with an empty replacement-listifndef 是否总是适用于使用空替换列表定义的类对象宏
【发布时间】:2013-06-25 12:49:30
【问题描述】:

头文件中的Include guards 通常用于保护代码段不被双重包含:

#ifndef FOOBAR_H
#define FOOBAR_H

extern void myfoofunc(void);

#endif

包含守卫通常依赖于这样的期望,即如果已经定义了类似对象的宏,则不会包含 #ifndef 块中的行——从而避免双重包含。

我注意到许多包含标题的#define 行有空的替换列表。 C99 标准是否保证用空替换列表定义的类对象宏将被#ifndef 视为“定义”?

在描述#define 的语法时,C99 标准似乎暗示第 6.10.3 节第 9 段中需要替换列表:

表单的预处理指令

#define 标识符替换列表换行

定义了一个类对象宏,它使宏名的每个后续实例都成为 替换为预处理标记的替换列表 构成指令的其余部分。替换名单是 然后重新扫描以下指定的更多宏名称。

这是否意味着包含标头应该采用以下形式:#define FOOBAR_H 1

【问题讨论】:

  • “C99 标准似乎暗示需要一个替换列表”——它没有这样的事情。看一下replacement-list的定义。

标签: c c99 c-preprocessor include-guards


【解决方案1】:

不,它没有。替换列表很可能是空的。 #define FOO 表示defined FOO 为真,但FOO 被替换为空。

例子:

#define FOO
#define BAR 1

#if defined FOO && defined BAR
int a = FOO + BAR ;
#endif

预处理结果:

int a = + 1 ;

【讨论】:

  • 在这种情况下,#if FOO == 1会成功,还是FOO实现的实际数值已定义?
  • FOO的值为空字符串。
  • 这是否意味着如果我使用#if 尝试将其与数值进行比较,我会得到一个编译器错误?
  • @VilhelmGray:你会的。 (你为什么不自己尝试一下?!)
  • @VilhelmGray "在这种情况下,#if FOO == 1 会成功" -- 扩展为 #if == 1。 “FOO 的实际数值”——没有这样的东西......预处理器进行文本/令牌扩展。
【解决方案2】:

replacement-list 的标准语法生成是:pp-tokens [opt]。因此,替换列表不需要任何标记。

所以#ifdef 可以正常工作,并且对于定义为“空”的宏可以正常工作。大量代码依赖于此。

【讨论】:

  • 啊,是的,我忽略了 第 6.10 节第 1 段 中的 语法 列表:replacement-list 被定义为 pp-tokens [opts],正如您所描述的。
【解决方案3】:

没有;宏替换不会发生在#ifndef 行中。如果是这样,那么整个语句将是一个语法错误(因为#ifndef 后面不会有任何内容)。

我想我确实见过#define FOOBAR_H 1 的一些实例,但这更多是个人喜好。

【讨论】:

    猜你喜欢
    • 2020-11-21
    • 2017-07-25
    • 1970-01-01
    • 2023-03-04
    • 2011-01-16
    • 2012-12-02
    • 1970-01-01
    • 2011-05-13
    • 2017-05-30
    相关资源
    最近更新 更多