【问题标题】:static vs non-static variables in namespace命名空间中的静态变量与非静态变量
【发布时间】:2012-07-22 08:00:08
【问题描述】:

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

foo.h:

namespace foo {
    int bar;
}

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

为什么会这样?更重要的是,为什么它工作没有static?在namespace 中使用static 是什么意思?

【问题讨论】:

    标签: c++ static namespaces


    【解决方案1】:

    另请注意,C++ 中命名空间(全局)范围内的const int 默认隐式添加了staticDefine constant variables in C++ header

    为了更好地理解发生了什么,在编译的中间 ELF 目标文件上做一个readelf,你会清楚地看到符号是否定义了两次。下面是一个详细的例子:What does "static" mean in C?

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

      • 但是如果头文件有包含保护,那么编译器只会包含头文件一次。那么,静态变量和非静态变量是一样的吗?
      • @ButterHub,包含保护在预处理阶段,以确保文件只包含一次。而静态变量的创建是在编译阶段。解析包含保护后,无论头文件可见 -> 在所有这些 .cpp 文件中创建静态变量。
      • 但是在预处理器将#include "File.h" 替换为File.h 的内容后,头文件在任何C++ 文件中都不再可见。编译器如何知道为多个文件创建静态变量? (第一个文件会有内容,但是包含保护阻止了更多文件获取它?)
      • @ButterHub,这在 cmets 中可能难以解释。您可以创建一个带有包含保护的 test.h 文件,并将其包含在 test1.cpp、test2.cpp、testN.cpp 中。然后在 g++ 中使用 -E 选项编译它们,以查看变量是如何在每个 .cpp 文件中声明的。例如"g++ -E test1.cpp > test1_show"
      • 谢谢@iammilind。我对预处理器如何处理包括警卫的误解是问题所在。即使存在包含保护,代码也会被替换到 每个 testX.cpp 文件中,如果它是“#include”的话。包含保护用于保护同一文件中的双重定义。
      【解决方案3】:

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

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

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

      【讨论】:

        【解决方案4】:

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

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多