不同版本可以防止重复包含头文件,这是正确的吗?

时间:2020-04-11 16:33:23

标签: c macros include c-preprocessor c99

如果我有一个名为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

4 个答案:

答案 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

出现在标题的开头,以代替基于条件编译的包含防护。