【问题标题】:No linker error when global variable declared static in the header file [duplicate]当全局变量在头文件中声明为静态时没有链接器错误[重复]
【发布时间】:2011-10-07 04:42:51
【问题描述】:

可能重复:
Static variables in C++

// x.h
int i = 3;

// x1.cpp
#include"x.h"
//...

// x2.cpp
#include"x.h"
//...

以上代码将给出链接器错误。但是,如果我声明,

//x.h
static int i = 3;

它不会在 gcc 中给出链接器错误,即使我们有相同的#include!我们是否为每个.cpp 文件创建不同的static int i;?它会导致任何静默链接错误(由于相同的名称)吗?

【问题讨论】:

  • @John,我正在编译 .cpp。让它也适用于 C++,因为它适用于 C 和 C++。
  • 你不能同时拥有它。它要么是 C++ 代码,要么是 C 代码。只选一个。如果您将代码编译为 C++,那么这不是 C 问题。
  • 我真诚地希望你为演示目的编写这个示例,名称像 i 的全局变量是通往(调试)地狱之路的东西......
  • @fvu 我想我们可以假设真正的文件名也不是 x.h。

标签: c++ linker static-variables


【解决方案1】:

编译 C 代码时,一次是一个“翻译单元”。早期,#includes 被扩展为引用文件的文本。所以你在静态情况下得到的相当于 x1.cpp 说static int i = 3; 和 x2.cpp 做同样的事情。而static 在这种情况下的意思大致是“不要与其他翻译单位分享”。

所以是的,当您使用 static 时,您会创建两个不同的 i 变量,它们彼此无关。这不会导致链接错误。

【讨论】:

    【解决方案2】:

    int x; 是实体x 的定义。 C++ 的单一定义规则说,任何使用的变量都应在程序中精确定义一次。因此出现错误。

    static 表示x 具有内部链接。也就是说,出现在one.cpptwo.cpp 中的x 是两个不同的不相关实体。

    C++ 标准说在这种情况下不推荐使用静态(根据史蒂夫的评论,在 C++0x 中不推荐使用)。匿名命名空间提供了更好的选择。

    namespace
    {
       int x;
    }
    

    还请注意,与 C 不同,在 C++ 中,标量类型的 const 变量也具有内部链接。那是

    const int x = 7; // won't give you an error if included in different source files.
    

    HTH

    【讨论】:

    • 请注意,C++0x FDIS 不赞成使用 static。而 C++03 从来没有真正解释过匿名命名空间版本在什么方面更胜一筹。
    【解决方案3】:

    我们是否在创建不同的静态 int i;对于每个 .cpp 文件?

    是的

    是否会导致任何静默链接错误(由于名称相同)?

    没有。由于静态,它们有不同的名称。

    如果这不是你想要的行为,你需要在头文件中使用extern,并在一个翻译单元(.cpp文件)中分配变量

    【讨论】:

      【解决方案4】:

      static 创建一个仅在单元内部可见的全局变量。

      如果您想在多个编译单元中使用变量,请在标头中使用extern,并在没有extern 的情况下在实现中声明它。

      【讨论】:

        【解决方案5】:

        在您的第一个代码示例中出现链接器错误,因为 i 是在两个编译单元中定义和导出的。在第二种情况下 i 是静态的,因此没有导出符号,因为静态变量仅在当前编译单元中可见并且不会导出到链接器。在这种情况下,您有两个独立变量,都称为 i。

        【讨论】:

          【解决方案6】:

          正如所写,代码看起来像是被多个 .cpp 文件访问相同的 i,而实际上,每个 .cpp 文件都有自己的副本。这可能会导致误解和错误。

          如果您希望只有一个i 的副本,首选的习惯用法是将其包装在x.h 的访问器函数中:

          int& GetI() {
            static int i = 3;  // this initialization only happens once.
            return i;
          }
          

          如果您确实想要为每个 .cpp 文件提供单独的 i 副本,更清晰的表达方式是在每个 .cpp 文件中单独声明 i

          namespace {
            int i;
          }
          

          为了安全起见,将其置于上述匿名命名空间中可防止其他 .cpp 文件对其进行访问。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-04-05
            • 1970-01-01
            • 1970-01-01
            • 2012-03-06
            • 2016-12-19
            • 2020-11-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多