多个包括具有变量定义的头文件

时间:2014-02-10 10:42:40

标签: c++

我只是构建一个简单的C ++项目。代码如下所示:

-------- head.h --------

#ifndef _HEAD_H_
#define _HEAD_H_

int my_var = 100;

#endif

-------- src1.cpp --------

#include "head.h"

-------- src2.cpp --------

#include "head.h"
int main() { return 0; }

我使用这些命令构建二进制文件:

g++ -c src1.cpp -o scr1.o
g++ -c src2.cpp -o src2.o
g++ -o a.out src2.o src1.o

但它在链接步骤失败并且告诉我我有“my_var”的多重定义。我不是只在头文件中使用安全保护宏吗?我不明白。有人知道为什么吗?

感谢。

PS: 如果我将my_var定义为一个静态变量,那么代码可以传递链接。我也不明白。

4 个答案:

答案 0 :(得分:3)

按以下方式更改标题

#ifndef _HEAD_H_
#define _HEAD_H_

extern int my_var;

#endif

例如,在带有main

的模块中添加行
#include "head.h"
int my_var = 100;
int main() { return 0; }

问题在于,由于标头包含在两个模块中,因此每个模块包含一个带有外部链接的变量,其名称与其他模块中的变量相同。并且链接器不知道要使用哪个变量。

答案 1 :(得分:2)

您每个编译单元一次定义my_var 。请记住,包括警卫在每个编译单元的基础上运行。

要解决此问题,您应该在标题中声明 my_varextern

#ifndef _HEAD_H_
#define _HEAD_H_

extern int my_var;

#endif
使用

在其中一个源文件中

定义

int my_var = 100;

然后链接器只能看到一个定义,一切都会好的。

答案 2 :(得分:1)

防护仅阻止标头在同一编译单元中被包含两次。

汇编src1.osrc2.o时,每个人都会包含my_var的定义。当您将它们链接到创建a.out时,编译器无法合并这些定义(即使它们是相同的),也会失败。

您要做的是将my_var声明为extern

---- head.h ----

#ifndef _HEAD_H_
#define _HEAD_H_

extern int my_var;

#endif

---- my_var.c ----

#include "head.h"

int my_var = 100;

然后编译所有源文件:

g++ -c my_var.cpp -o my_var.o
g++ -c src1.cpp -o scr1.o
g++ -c src2.cpp -o src2.o
g++ -o a.out my_var.o src2.o src1.o

这样,my_var将在每个文件中声明,但只会在my_var.o定义。这里有一个重要的区别。尝试省略链接my_var.o,您将看到编译器要说的内容:)

答案 3 :(得分:0)

你的问题归结为理解C ++存储类;静态和外部更准确。

extern says: this variable is defined in a different file, this 
             is only a declaration
static says: this variable's lifetime is the program lifetime and
             restrict it's visibility to the current file. 



What happens in your case:
   - each file includes the variable declaration and definition `int my_var = 100;`,
     so both object scr1.o and scr2.o will contain the variable definition. When
     linking them, the linker cannot solve the ambiguity and throws an error.
   - adding the extern qualifier and defining the variable in one of the files 
     solves this problem: in one source it'll be an external unresolved at compile
     time, symbol and the other will contain the actual symbol.

关于你问题的第二部分;为什么添加静态似乎有助于链接器。看看我刚才所说的静态存储类:基本上每个对象都有自己的变量副本 - 不一样!