【问题标题】:What does #define without assignment assign to in C?在 C 中没有赋值的 #define 分配给什么?
【发布时间】:2021-09-18 12:43:00
【问题描述】:

我经常看到类似的代码

#ifndef HEADERFILE_H
#define HEADERFILE_H
// some declarations in
// the header file.
#endif

我想知道#define HEADERFILE_HHEADERFILE_H 定义为什么?

我试过了

cout<<HEADERFILE_H<<endl;

但我得到了

error: expected expression

【问题讨论】:

  • 如果你 #define TEST 之后在某处使用它,TEST 将被替换为空。例如:int x = foo(TEST); 等价于 int x = foo();。正如@ThomasJager 指出的那样,在这种情况下,“空”#define 仅用于包含标题一次。
  • 您似乎在中途切换语言。你说的是 C,但代码是 C++。是哪个?
  • 想用printf但不知道类型,所以用cout

标签: c c-preprocessor


【解决方案1】:

define 预处理指令的格式为 # define <i>identifier</i> <i>preprocessing-tokens</i>,以换行符结尾。 <i>preprocessing-tokens</i> 是零个或多个预处理标记的列表。它可能是空的,也就是说,它可能有零个标记。这意味着,当在发生宏替换的地方遇到<i>identifier</i> 时,它将被替换为空。1

#ifdef <i>identifier</i>#ifndef <i>identifier</i>define <i>identifier</i> 形式的测试在 #if#elif 指令中测试是否定义了 <i>identifier</i>。如果它没有被定义(或者它的定义被#undef 指令删除了),那么测试表明它没有被定义。如果已定义,则测试表明已定义,即使定义是针对零标记的。

零标记的定义与没有定义完全不同,defined <i>identifier</i> 将评估前者为真,后者为假。

脚注

1 如果列表确实有标记,则<i>identifier</i> 将被替换为这些标记,并且将应用其中的### 运算符。预处理标记主要是标识符(如foo34)、常量(如34u1.8e4)、C 运算符之一或特殊字符(如*+=) ,或 C 语言的某些其他组件。

【讨论】:

  • 你的意思是说预处理器维护一个标识符到预处理器令牌的映射。在我的情况下,唯一的事情是预处理器令牌是空的? #undef 还会从地图中删除吗?
  • @Heroman:由每个 C 编译器(或其他 C 实现)以某种方式管理其数据。 C 标准只是说明使用宏替换和#define 指令会产生什么行为,而不是编译器必须如何实现它们。大多数编译器可能会维护一个映射或类似的东西。
【解决方案2】:

它实际上定义了“除了它自己”。那就是:你可以定义一个宏而不给它一个特定的值。由于您可以检查给定宏是否已定义,因此您可以询问给定宏的简单“存在”。

这对于指示上下文(例如,如果您正在为给定的操作系统进行编译)和/或某些资源的可用性很有用。

在这个特定的例子中,这是一个所谓的“守卫”:如果之前没有这样做,它会定义自己,并且包括文件的其余部分,它完全嵌入在#ifdef … #endif子句。

这用于实现一种require_once,如果需要,它会被包含在内,但不会被多次包含。例如,当您在全局范围内定义函数或声明变量时,这是必需的。

【讨论】:

  • 谢谢,你说的“除了它自己”是什么意思。是数值吗?我想知道内部情况。
  • #define HEADERFILE_H 没有将HEADERFILE_H 定义为“自身”,因此它没有将其定义为“除了自身之外别无其他”。它将HEADERFILE_H 定义为预处理器标记的空序列。
【解决方案3】:

这是一个语言习语(我会评论它):

#ifndef HEADERFILE_H

在此和最后一个 #endif 之间,所有内容都包含在编译中,但前提是之前未定义 HEADERFILE_H

#define HEADERFILE_H

我们在block中做的第一件事就是#define这个标识符,所以下次再找这个fragment时,#ifndef#endif之间的内容就不会再是#included了(因为标识符声明)。

// some declarations in
// the header file.

这个块只会被包含一次,即使你#include这个文件多次。

#endif

这标志着受保护块的结束。

通常会包含一些文件,实际上,#includes 另一个文件,而该文件包含另一个文件,导致您不知道哪些文件已包含,哪些不包含。这种措辞允许您受到保护,并且能够多次#include 同一个文件(通常您不能,因为某些定义不能在同一个编译单元中重复,例如声明)上面的行将包含内容并定义标识符,使下一个包含(有效地完成)不包含内容,因为标识符在第二次和后面的时间显示为#definen

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-16
    • 1970-01-01
    • 2011-03-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多