当全局变量在头文件中声明为静态时,没有链接器错误

No linker error when global variable declared static in the header file

本文关键字:链接 错误 静态 全局变量 文件 声明      更新时间:2023-10-16

可能重复:
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;?它会导致任何静默链接错误(由于相同的名称(吗?

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

是的,当你使用static时,你会产生两个不同的i变量,它们彼此无关。这不会导致链接错误。

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

static认为x具有内在联系。也就是说,出现在one.cpptwo.cpp中的x是两个不同的不相关实体。

C++标准表示,在这种情况下不赞成使用static(根据Steve的评论,在C++0x中,这是不赞成的(。匿名命名空间提供了一种优越的替代方案。

namespace
{
   int x;
}

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

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

HTH

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

它会导致任何静默链接错误(由于相同的名称(吗?

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

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

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

如果您想在多个计算单元中使用一个变量,请在标头中使用extern,并在不使用extern的实现中声明它。

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

在编写时,代码看起来像是多个.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文件访问它。