56

我有一个foo包含整数的命名空间bar,声明如下...

富.h:

namespace foo {
    int bar;
}

现在,如果我foo.h只包含在一个文件中,这工作得很好。但是当我包含两个或多个文件时会出现问题foo.h:我收到链接器错误。我发现如果我声明barstatic,我可以包含foo.h在多个文件中。这对我来说似乎很奇怪,因为我不知道可以在命名空间内声明一个静态变量。(那有什么意思?)

为什么这行得通?更重要的是,为什么没有它就不能 static工作?在 a 中使用时是什么static意思namespace

4

4 回答 4

55

static在不同的上下文中有多种含义。在这个特定的上下文中,这意味着变量具有内部链接,因此包含该标题的每个翻译单元都将拥有自己的变量副本。

请注意,虽然这将使链接器错误保持沉默,但它会foo::bar为生成的每个目标文件维护一个单独的变量(更改在不同的目标文件中不可见)。

如果你想要一个变量,你应该extern在标题中声明它,并在一个翻译单元中提供一个定义。

于 2012-07-24T02:56:45.433 回答
37

当您将变量声明为static时,这意味着它的范围仅限于给定的翻译单元。没有static范围是全局的。

当您static在 .h 文件中声明一个变量(在或没有namespace; 无关紧要),并将该头文件包含在各种 .cpp 文件中时,该static变量将成为每个.cpp文件的本地范围。
所以现在,每个包含该标头的 .cpp 文件都将拥有该变量的自己的副本。

如果没有static关键字,编译器将只生成该变量的一个副本,因此一旦您将头文件包含在多个 .cpp 文件中,链接器就会抱怨多个定义。

于 2012-07-24T02:55:55.857 回答
7

问题是由变量的多个定义引起的。不同翻译单元中的定义相互冲突,就像多个非内联函数定义不起作用一样。

当您将变量设为静态时,您将赋予变量内部链接,因此每个翻译单元都有自己的独立副本。

您可能真正想要的只是将声明放在头文件中(使用 extern),然后将定义放在实现文件中。

于 2012-07-24T02:59:11.477 回答
1

另请注意,默认情况下const int,C++ 中的命名空间(全局)范围已static隐式添加:Define constant variables in C++ header

为了更好地理解发生了什么,readelf在编译的中间 ELF 目标文件上做一个,你会清楚地看到符号是否定义了两次。这是一个详细的示例:“静态”在 C 中是什么意思?

于 2018-11-29T14:20:53.013 回答