为什么编译器没有为错误的 extern 声明发出错误?

Why the compiler issues no error for erroneous extern declaration?

提问人:Nick 提问时间:7/16/2016 更新时间:9/14/2017 访问量:236

问:

在 file1 上,我将变量 args 定义为:

CLA args;

在 file2 中,我将其声明为:

extern CLA* args;

该程序将使用 gcc 和 clang 编译而不会出现错误,并且在 valgrind 上也不会出现任何错误。但有一个问题:在 file2 上,函数 fprintf(args->output, ...) 不会打印任何内容。为什么没有发出错误?

c 海湾合作委员会

评论

0赞 David Schwartz 7/16/2016
试着想象一下在这种情况下会发出一个合理的编译器错误。我不认为你能做到。我的机器上有一个 file3,它声明为 .你的编译器应该警告这一点吗?argsint
2赞 Jonathan Leffler 7/16/2016
这就是为什么你需要一个标头来声明变量(如果你真的必须使用全局变量),然后标头被两个源文件都包含,并充当引用者——这将导致编译器拒绝错误的文件。请参阅如何在 C 语言中使用 extern 在源文件之间共享变量?

答:

5赞 Jonathon Reinhart 7/16/2016 #1

该程序将使用 gcc 和 clang 编译,而不会出现错误

因为每个 C 文件都是独立编译的。链接生成的目标文件时,链接器仅具有符号名称。它不知道与这些符号关联的类型

这是 C++ 使用名称修改的原因之一1:符号的类型嵌入在其名称中,因此如果出现不匹配,就会发生链接失败。

这就是为什么你要么不使用全局变量,要么在头文件中声明它们,并在你引用所述全局的所有地方都包含该头文件,包括定义它的单位

永远没有理由出现在文件中;仅在文件中。extern.c.h

valgrind 上也不会出现任何错误。

我们还没有看到您的源代码,因此我们无法知道您是如何错误地使用所述变量的,以至于 valgrind 会检测到它。


1 - 另一个主要原因是支持重载函数。

评论

0赞 Jonathan Leffler 9/14/2017
C++ 全局变量的名称会被篡改吗?Mac 上的 GCC () 7.2.0 编译为根据 定义的目标文件。g++int gobbledygook = 13;0000000000000000 D _gobbledygooknm
2赞 Rudy Velthuis 7/16/2016 #2

请改为执行以下操作:

创建一个头文件,我们称之为 。它应如下所示:globals.h

#ifndef GLOBALS_H
#define GLOBALS_H

/* include whatever you need, declare the CLA type */

extern CLA *args;

/* define/declare/etc. whatever you need here. */

#endif

在第一个文件中,执行以下操作:

#include "globals.h"

在第二个文件中,执行以下操作:

#include "globals.h"

/* rest of code here */

CLA *args = NULL;

/* more code here */