【C++】extern

本文介绍一些externC++中的用法

声明与定义分离

C++程序员应该都知道单一定义规则ODR

在任何一个翻译单元中,只允许存在任何变量、函数、类类型、枚举类型 、概念 (自 C++20 起) 或模板的一个定义(其中一些可能具有多个声明,但只允许一个定义)。 在整个程序(包括任何标准库和用户定义的库)中,需要出现每个非 内联 函数或变量的一个且仅一个定义,这些函数或变量是 odr-使用 的(见下文)。 编译器不要求诊断此违规行为,但违反它的程序的行为是未定义的。

具体来说,如果在头文件中初始化一个变量,在多个源文件包含此头文件,在联合编译时,就会报重定义的错误。

global.h

int global_int = 1;

global1.cc

#include "global.h"

global2.cc

#include "global.h"

int main()
{
    return 0;
}

使用以下命令,联合编译多个文件:

g++ global1.cc global2.cc -o main

结果编译报错:

/tmp/cc4Y38ub.o:(.data+0x0): global_int 的多重定义
/tmp/ccSwS0de.o:(.data+0x0):第一次在此定义
collect2: 错误:ld 返回 1

正确的做法是在头文件中使用extern声明,在源文件中定义。

global.h

extern int global_int;

globa1.cc

#include "global.h"

int global_int = 1;

global2.cc

#include "global.h"
#include 

extern int global_int;

int main()
{
    std::cout << global_int << std::endl;
    return 0;
}

最后打印的结果为1.

更一般的做法是,在头文件声明外部变量,在对应的源文件初始化。此时在其他的源文件读取或者修改这个变量,达到跨文件全局变量的效果。在单线程场景下,这种做法十分有效。

以C语言的方式编译函数

在 C++ 里,为支持函数重载和类成员函数等特性,编译器会对函数名、类名等进行修饰,让它们在符号表中保持唯一。可以参考我写的这篇文章:【C++】filt工具的使用

比如刚才的代码:

#include 

int get_int()
{
    return 1;
}

int main()
{
    std::cout << get_int() << std::endl;
    return 0;
}

编译后对get_int提取名字:

0000000000400806 T _Z7get_intv

C语言是没有这个机制的,因为C语言不支持重载,当我们需要将代码打包为C接口供外部调用时,比如【Python】多线程/进程操作C++代码,就需要去掉这种修饰。

此时可以用extern "C"对函数调用进行包裹。编译器会按C语言的风格编译代码:

#include 

extern "C"
{
    int get_int()
    {
        return 1;
    }
}

int main()
{
    std::cout << get_int() << std::endl;
    return 0;
}

此时提取名字:

0000000000400806 T get_int

可以看到,名称修饰已经去掉了。

你可能感兴趣的:(#,C++,编程语言,c++,开发语言)