【问题标题】:Definition and declaration of global variables using preprocessor trick使用预处理器技巧定义和声明全局变量
【发布时间】:2013-12-12 16:00:05
【问题描述】:

我目前正在查看高级工程师编写的代码。代码运行良好,但我正在尝试找出一个细节。

他使用了很多全局变量,并且他的代码被分解成许多单独的文件。因此,他使用了一种技术来确保在需要访问全局变量的任何地方都声明了全局变量,但只定义了一次。

这项技术对我来说是新的,但我在互联网上阅读了几篇文章并对它的工作原理有所了解。他用

#undef 外部

后跟 EXTERN 的条件定义为空字符串或实际的 extern。有一篇很好的文章 here 解释了它是如何工作的。还有一个讨论here

让我感到困惑的是,我在网上看到的所有示例都建议在所有需要它的源文件中以常规方式包含头文件,除了一个。在这个包含标题的单个特殊情况行之前,定义了一个符号,该符号将确保将 EXTERN 定义为空字符串,等等(参见上面的链接)。通常,这种单一的特殊情况在 main 文件中或专用于声明全局变量的单独源文件中。

但是,在我正在查看的代码中,这种特殊情况是 always 在对应于标头的源文件中。这是最小的例子:

peripheral1.h”:

#undef EXTERN
#ifndef PERIPHERAL_1_CPP
#define EXTERN extern
#else
#define EXTERN
#endif

EXTERN void function1(void);

peripheral1.cpp”:

#define PERIPHERAL_1_CPP
#include "peripheral1.h"

function1()
{
    //function code code here
}

他刚刚在代码中的所有其他地方

#include "peripheral1.h"

我的问题是如何以及为什么会起作用?换句话说,编译器如何知道在哪里定义以及在哪里声明函数(或变量,或类......)?为什么在上面的例子中可以有这些行:

#define PERIPHERAL_1_CPP
#include "peripheral1.h"

在实际的 peripheral1.cpp 中而不是在 main.cpp 或其他地方?

或者我在这里遗漏了一些明显的东西?

【问题讨论】:

  • 我真的不明白这一点。函数不需要声明extern,您可以在标题extern 中声明全局变量,然后在不使用这些预处理器宏的情况下在没有extern 的.cpp 文件中定义它们。
  • @Simple,有了这个“技巧”,你只需要编写每个变量声明一次,而不是两次。
  • 听起来他不应该再做高级工程师了。

标签: c++ global-variables preprocessor


【解决方案1】:

除“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。完全清楚...

换句话说,编译器如何知道在哪里定义和在哪里 只声明函数(或变量,或类...)?

每当遇到语法结构时,编译器就知道在哪里声明,该语法结构在标准中定义为具有声明的语义。 编译器知道在哪里定义,只要它遇到一个语法结构,它在标准中被定义为具有定义的语义。

换句话说,编译器不知道 - 你明确告诉它你想让它做什么。

【讨论】:

  • 感谢您的回答,但它没有回答我的问题。请在上面查看我对 Nostalgia 回答的评论
  • 您已经描述了“如何”。我已经回答了“为什么”——因为 C 标准将某些 C 语言构造(上面的示例)定义为声明,而将某些其他构造(上面的示例)定义为定义。抱歉,如果不够清楚。
  • 这不是真的。 C++ 没有暂定定义。
【解决方案2】:

怀旧

啊,这让我回到了公平的道路(大约 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

这样,您可以在整个代码中,甚至在每个代码文件中,根据需要多次#include 文件,并且您将避免多个定义错误。公平地说,我通常使用 .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 文件上尝试过,但今晚会看看是否有任何好处:)

如果您需要更多信息,请告诉我:)

【讨论】:

  • 感谢您的回答。也许我没有正确表达我的问题。我确实了解这些技术。在提出问题之前,我提供了两个链接来证明我已经研究过它。实际的问题是:为什么我在 peripheral1.cpp 中看到 #define PERIPHERAL_1_CPP #include "peripheral1.h" 行,但在 main 或其他地方却没有?还是我还想念什么
  • 简而言之,代码的目的是在“peripheral1.cpp”中定义函数,并在包括“main”在内的所有其他源文件中使用它。因此它也在“main”中声明。
猜你喜欢
  • 1970-01-01
  • 2021-05-29
  • 2013-06-05
  • 1970-01-01
  • 1970-01-01
  • 2011-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多