为什么我不能在标题中定义一个非const gloabal变量?如果我使用命名空间为什么我必须声明它' extern'?

时间:2018-01-18 00:49:12

标签: c++

1)我知道非const变量是默认的外部链接(它已经或多或少被声明为外部)但我不明白为什么我不能定义一个全局变量,如标题中的int glbl_a

//test.h
#ifndef TEST_H
#define TEST_H
int glbl_a=0;   //wrong -> "multiple definition of `glbl_a`"    
static int st_glbl_a=1; //ok to initialize it in header!
extern int ext_glbl_a; //ok to declare it and define it in test.cpp
#endif
//test.cpp

#include "test.h"
using namespace std;

//st_glbl_a=22; i could use st_glbl_a but it wouldn't affect st_glbl_a in main cause of 'static'    
int ext_glbl_a=2; //definition of external gloabal non-const variable
//main.cpp

#include <iostream>
#include "test.h"
using namespace std;

extern int glbl_a; //declaration of glbl_a external
int main(){
 cout<<glbl_a;
}

这个程序的工作版本是我只在test.cpp中定义int glbl_a=0;并在main中声明extern int glbl_a;然后在输出中使用它(test.h中的定义刚评论,这与glbl_a)无关。

2)如果我将所有定义/声明分组到扩展到test.cpp和test.h(MyNamespace)的命名空间中,则工作版本不再起作用了int glbl_a的.cpp:

//test.h
#ifndef TEST_H
#define TEST_H
namespace MyNamespace{
//extern int glbl_a;
}
#endif
//test.cpp

#include "test.h"
using namespace std;
namespace MyNamespace{
 int glbl_a=0;
}
//main.cpp

#include <iostream>
#include "test.h"
using namespace std;

int main(){
 cout<<MyNamespace::glbl_a; //wrong -> "'glbl_a' is not a member of 'MyNaspace'"
}

只有当我在test.h中对声明进行解除评论时才会起作用,但为什么呢?

2 个答案:

答案 0 :(得分:3)

问题1

包含标题会有效地将包含的文件粘贴到包含文件中,生成一个大文件,然后编译(通常会立即删除)。这意味着每个包含文件现在都有自己的glbl_a。编译器很高兴,但是当链接器尝试将所有内容放在一起时,它会找到名称glbl_a的许多同等有效的伪装者。链接器讨厌这个,甚至没有试图找出你想要做的事情。它只是吐出一条错误消息,并要求您解决问题。

问题2

test.cpp和main.cpp是不同的translation units。他们编译生成不同的,完全独立的对象。两者都看不到另一个,所以test.cpp中存在MyNamespace::glbl_a的事实在main.cpp上丢失了。编译main.cpp时,编译器会构建一个在main.cpp构造的文件中声明的标识符列表及其包含的所有头文件。 MyNamespace::glbl_a永远不会在第一次使用时(或之后)声明,因此编译器会发出错误消息。

在test.h中取消注释声明意味着编译器将在main.cpp中找到MyNamespace::glbl_a并允许它使用。由于MyNamespace::glbl_a在test.cpp中定义,因此链接器可以找到一对一MyNamespace::glbl_a并且可以成功链接。

extern不分配存储空间。相反,它是对编译器的承诺,即声明的变量将被完全定义并在其他地方分配,可能在文件的后面或在另一个文件中。变量存在于某处,编译可以继续。如果链接器找不到定义,链接器会将其称为骗子。

此处有更多详情:How does the compilation/linking process work?

有关externWhen to use extern in C++Storage class specifiers

的更多信息

答案 1 :(得分:0)

标题将包含在其他文件中(多个),因此如果您在标题中定义,它将在每个翻译单元中导致“多重定义”