如果我有一个名为test.h
的文件,并且想要防止它的重复包含(以防止链接器错误),我被告知键入:
#ifndef TEST_H_INCLUDED
#define TEST_H_INCLUDED
但是我看到了多个版本,例如一个告诉我写:
#ifndef TEST_H
#define TEST_H
有什么区别,为什么我不能像这样简单地使用文件的原始名称:
#ifndef test.h
#define test.h
编辑:如果test.h
之后的名称并不重要并且可以是,可以使预处理器如何知道我试图防止重复包含名为#ifndef
的头文件。像:#ifndef Dummy
之类的东西,如果我不打算使用名称,那么使用它们还有什么意义呢?如果它们使它更简单并且让我们只输入:
#ifndef
#define
答案 0 :(得分:2)
前两个选项在语义上是等效的,而“更好”是主观的(前一个更清晰,但涉及更多类型)。
第三个选项是不可能的,因为C中的宏只能包含字母,数字(但不能作为第一个字符)和下划线。这些规则与任何其他类型的标识符(例如,变量和函数名称)相同。有关更多详细信息,请参见此cppreference页。
答案 1 :(得分:2)
[..]有什么区别
没有任何区别。宏名称可以是任何名称,并且约定使用标头名称,并用下划线(JTextField
)分隔。
为什么我不能像这样简单地使用文件的原始名称
宏名称中不能包含TEST_H
。所以这是不允许的。标识符的相同规则也适用于宏名称。参见6.4.2 Identifiers。
您可以改为:
.
或:
#ifndef test_h
#define test_h
#endif
不过,惯例是,所有大写字母都应使用点号替换为下划线,并可能使用前导/尾随下划线。
以下面的代码示例(不等同于宏-仅出于说明目的):
#ifndef test_header
#define test_header
#endif
此处int flag = 0;
if (flag == 0) {
/* include this content */;
flag = 1;
}
else {
/* not included */
}
与宏名称等效。这就是名称本身不重要的原因。重要的是是否设置了flag
。
它们应该使它更简单并且让我们只输入:
#ifndef
#define
不幸的是,这不是有效的语法。
我理解普遍的问题,并同意这样做应该更好/更容易。但这是历史性的。预处理器是一个古老的东西(至少从70年代初期开始),现在它不会改变了:)
答案 2 :(得分:1)
前两个定义选项没有什么不同。不接受最后一个选项,因为预处理器不接受(.)
作为标识符的一部分。
有时候,有必要选择要包含在程序中的几个不同的头文件之一:
#if SYSTEM_1
# include "test1.h"
#elif SYSTEM_2
# include "test2.h"
#endif
您只需输入一个宏名称:
#define SYSTEM_1 "test1.h"
...
#include SYSTEM_1
更新:
您不能使用:
#ifndef
#define
预处理器需要一个宏名称。就像if ... else
语句。您不能if () {} else {}
。
您可以定义任何您不想使用的事件。
#ifndef NOTUSE
#define NOTUSE
例如,当您要调试时,可以定义DEBUG
并在需要时使用它。
#ifdef DEBUG
printf(" debug here\n");
#endif /* DEBUG */
如果您未定义DEBUG
,则printf
函数将无法运行。
答案 3 :(得分:1)
问题的观点似乎在编辑的摘要中得到了很好的总结:
编辑:预处理器如何知道我试图防止重复包含名为
test.h
的头文件,如果后面的名称#ifndef
不重要,可以是#ifndef Dummy
,
预处理器不知道您是在专门尝试阻止多重包含,也没有任何关于您要保护的头文件名称的可操作的信息。这是预处理器的通用条件编译机制在解决(实际上并未阻止)多重包含的特定问题中的应用。
,如果我不打算使用名称,那还有什么用呢? [...]
但是您要做使用它。在#ifndef
指令中。那里引用的宏名称与#define
d相同,对于这种机制的正常运行至关重要。
该机制利用以下事实:预处理器可以测试是否定义了特定的宏名称,并将结果用作是否编译源文件的关联节的条件。这就是#ifndef
... #endif
的含义。 #define
确保编译之间的部分会导致定义指定的预处理器宏,以便#ifndef
条件在随后包含相同的标头时求值为false。因此,宏名称的具体选择并不重要,但是与其他标头使用的所有宏名称不同(或者如果有意这样做则不是)的事实是很重要的。
它们应该使它更简单并且让我们只输入:
#ifndef #define
同样,这是通用机制的特定应用。通用机制用于定义预处理器宏以及测试是否定义了宏,这些宏是较大的预处理器宏工具的一部分。此功能根据特定的宏名称起作用。此外,即使是明智的选择,空的宏名称也无法满足此目的,因为(如果通常使用)空的宏名称将无法满足使用不同宏名称的每个标头的必要条件。
但是,某些C实现与您一致认为标头保护符可能更容易。 作为通用(但不是通用!)扩展,某些实现可以识别
#pragma once
出现在标题的开头,以代替基于条件编译的包含防护。