我目前正在查看高级工程师编写的代码。代码运行良好,但我正在努力找出一个细节。
他使用了相当多的全局变量,他的代码被分解成许多单独的文件。因此,他使用了一种技术来确保全局变量在他需要访问它们的任何地方都被声明,但只定义了一次。
这项技术对我来说是新的,但我在互联网上读了几篇文章,对它的工作原理有了一些了解。他使用
#undef EXTERN
然后将EXTERN条件定义为空字符串或实际的EXTERN。这里有一篇非常好的文章解释了它的工作原理。这里还有一个讨论
让我感到困惑的是,我在网上看到的所有例子都建议以常规方式将头文件包含在所有需要它的源文件中,只有一个例外。在这个特殊情况下,包含标头的行前面是一个符号的定义,该符号将确保EXTERN将被定义为空字符串和。。依此类推(请参阅上面的链接)。通常,这一特殊情况在主文件中或在专用于全局变量声明的单独源文件中。
然而,在我看到的代码中,这种特殊情况是总是在与标头对应的源文件中。这里是一个最小的例子:
"外围1.h":
#undef EXTERN
#ifndef PERIPHERAL_1_CPP
#define EXTERN extern
#else
#define EXTERN
#endif
EXTERN void function1(void);
"外围1.cpp":
#define PERIPHERAL_1_CPP
#include "peripheral1.h"
function1()
{
//function code code here
}
在代码的其他地方,他只是做
#include "peripheral1.h"
我的问题是如何以及为什么这样做?换句话说,编译器如何知道在哪里定义,在哪里声明函数(或变量,或类…)?为什么在上面的例子中有这样的行是可以的:
#define PERIPHERAL_1_CPP
#include "peripheral1.h"
在实际的外设1.cpp中,而不是在main.cpp或其他地方?
还是我遗漏了一些显而易见的东西?
除"perripheral1.cpp"外,预处理后的所有源文件都包含一个序列的外部变量声明,如:
extern int a;
extern int b;
extern int c;
仅在peripheral1.cpp
中,经过预处理后,将有一系列声明:
int a;
int b;
int c;
int d;
它们是相应变量的暂定定义,在正常情况下相当于外部定义:
int a = 0;
int b = 0;
int c = 0;
int d = 0;
最终的结果是,变量在所有地方都被声明,但只定义了一次。
PS。为了完全清楚。。。
换句话说,编译器如何知道在哪里定义以及在哪里定义只声明函数(或变量,或类…)?
每当遇到语法结构时,编译器都知道在哪里声明,该语法结构在标准中定义为具有声明的语义。编译器知道在哪里定义,无论何时遇到语法结构,该语法结构在标准中定义为具有定义的语义。
换句话说,编译器不知道-你明确地告诉它你想让它做什么。
怀旧
啊,这让我倒退了一段时间(大约20年左右)。
这是C代码在多个文件中定义全局变量的一种方式:使用宏定义变量一次,以确保只定义一次,然后将其外部化到其他C代码文件中,以便使用它。如今,在许多情况下,它是多余的,但它在遗留代码中仍然有其位置,并且(很可能)仍将在许多现代编译器中工作,这是C代码而不是C++。
通常使用类似#define PERIPHERAL_1_CPP
的方法来确保包含的唯一性,如#pragma once
在我自己的代码中,我会使用类似的东西:
#ifndef PERIPHERAL_1_CPP
#define PERIPHERAL_1_CPP
// my includes here
// my code here
#endif
这样,您就可以在代码中多次#包含该文件,甚至在每个代码文件中,这样就可以避免多个定义错误。公平地说,我通常使用.h文件,并有类似的东西:
// for absolutely insane safety/paranoia
#pragma once
// normally sufficient
#ifndef PERIPHERAL_1_H
#define PERIPHERAL_1_H
// my includes here
// my code here
#endif
我从来没有在cpp文件上尝试过,但今晚我会看看是否有任何好处:)
如果你需要更多信息,请大声告诉我:)