编译单元之间共享的全局const对象

all*_*ter 6 c++ const global-variables hyperlink

当我声明并初始化一个const对象时.

// ConstClass.h
class ConstClass
{
};

const ConstClass g_Const;
Run Code Online (Sandbox Code Playgroud)

两个cpp文件包含此标头.

// Unit1.cpp
#include "ConstClass.h"
#include "stdio.h"

void PrintInUnit1( )
{
    printf( "g_Const in Unit1 is %d.\r\n", &g_Const );
}
Run Code Online (Sandbox Code Playgroud)

// Unit2.cpp
#include "ConstClass.h"
#include "stdio.h"

void PrintInUnit2( )
{
    printf( "g_Const in Unit2 is %d.\r\n", &g_Const );
}
Run Code Online (Sandbox Code Playgroud)

当我构建解决方案时,没有链接错误,你会得到什么如果g_Const是一个非const基本类型!

PrintInUnit1()和PrintInUnit2()表明在两个编译单元中有两个独立的"g_Const"具有不同的地址,为什么?

==============

我知道如何修复它.(使用extern关键字进行声明,并在一个cpp文件中定义它.)

我想知道为什么我在这个示例中没有得到redfined链接错误.

小智 9

/sf/answers/432172261/

命名空间范围内的const变量具有内部链接.所以它们基本上是两个不同的变量.没有重新定义.

3.5/3 [basic.link]:

具有命名空间作用域(3.3.5)的名称具有内部链接(如果它的名称)

- 明确声明为静态的对象,引用,函数或函数模板,或

- 显式声明为const的对象或引用,既未显式声明为extern,也未声明为具有外部链接; 要么

- 匿名联盟的数据成员.

使用extern,如果你希望它有外部链接.


如另一个答案所述,头文件只是粘贴在cpp文件中.两个cpp文件中都包含相同的头文件,但它们是单独的转换单元.这意味着变量的一个实例与另一个实例不同.另一方面,让编译器知道您已在其他地方定义了变量,请使用extern关键字.这确保了翻译单元之间只共享一个实例.然而,extern const Test test这只是一个声明.你需要一个定义.只要在某个cpp文件中定义了一次就定义它并不重要.您可以根据需要多次声明它(这样可以方便地将其放在头文件中.)

例如:

Constant.h

class Test
{
};

extern const Test test;
Run Code Online (Sandbox Code Playgroud)

Unit1.cpp

#include "Constant.h"
#include <iostream>

void print_one()
{ std::cout << &test << std::endl; }
Run Code Online (Sandbox Code Playgroud)

Unit2.cpp

#include "Constant.h"
#include <iostream>

void print_two()
{ std::cout << &test << std::endl; }
Run Code Online (Sandbox Code Playgroud)

main.cpp中

extern void print_one();
extern void print_two();

int main()
{
   print_one();
   print_two();
}
Run Code Online (Sandbox Code Playgroud)

Constant.cpp

#include "Constant.h"
const Test test = Test();
Run Code Online (Sandbox Code Playgroud)

Makefile文件

.PHONY: all
all:
   g++ -std=c++11 -o test Constant.cpp Unit1.cpp Unit2.cpp main.cpp
Run Code Online (Sandbox Code Playgroud)


dra*_*135 5

因为您将变量定义放在头文件中.包含头文件就像用文件内容替换它一样.那么,第一个文件:

// Unit1.cpp
#include "ConstClass.h"  // this will be replace with the content of ConstClass.h
#include "stdio.h"

void PrintInUnit1( )
{
    printf( "g_Const in Unit1 is %d.\r\n", &g_Const );
}
Run Code Online (Sandbox Code Playgroud)

将成为(在编译之前的预处理阶段):

// Unit1.cpp
// ConstClass.h
class ConstClass
{
};

const ConstClass g_Const;
//this line is replaced with the content of "stdio.h"

void PrintInUnit1( )
{
    printf( "g_Const in Unit1 is %d.\r\n", &g_Const );
}
Run Code Online (Sandbox Code Playgroud)

第二个文件将是:

// Unit2.cpp
// ConstClass.h
class ConstClass
{
};

const ConstClass g_Const;
//this line is replaced with the content of "stdio.h"

void PrintInUnit2( )
{
    printf( "g_Const in Unit2 is %d.\r\n", &g_Const );
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,每个文件都有单独的变量g_Const(这只是针对您的代码的情况,可能根本没有像宏一样的变量,请参阅我上一段中的解释).

如果你想要的不是变量的定义,而只是头文件中的声明,你应该extern在头文件中使用关键字:

extern const ConstClass g_Const;
Run Code Online (Sandbox Code Playgroud)

然后你可以把g_Const变量的定义放在ConstClass.c


您的代码中有一些问题:

  • 在您的g_Const定义中没有分配常量值,您必须在定义中为其分配一个常量值,除非您想要默认值(0).
  • 在printf中,你获取constC++变量的地址.这实际上迫使编译器在堆栈中创建变量.如果你不接受地址,它可能能够推断出在C中表现得像宏的编译时间数(你可以直接将幻数放在你使​​用const变量的代码中).