C/C++中的extern关键字详解

extern关键字

extern是c/c++语言中的一个关键字,用在变量或函数前面,作用是说明这个变量或函数是在别处定义的,要在此处引用

补充说明,在c/c++中,函数默认具有外部链接性,即可以不使用extern修饰函数
第一种情况,在一个源文件(c或cpp源文件)中,在前面的代码中引用后面定义的变量或函数;c/c++编译器要求在使用标识符之前必须有其声明,如果在前面的代码中使用后面声明定义的内容理论上是会报错的,通过extern告诉编译器这个变量/函数是在其他地方定义的

c 复制代码
int main() {

    extern int var_main; // 只能声明,不能赋值
    extern void func_main();

    func_main();

    printf("main(), var_main = %d\n", var_main);

    return 0;
}

int var_main = 100;

void func_main() {
    printf("func_main(), var_main = %d\n", var_main);
}

这里不得不提一下c/c++编译的流程:c/c++程序从源码到可执行文件,一共两个阶段,编译和链接

  1. 编译:将c/c++文件编译成目标文件(.o/.obj),这个阶段编译器只负责语法检查和生成机器指令的雏形,并不关心变量或函数的真正地址;
  2. 链接:编译器将所有的目标文件、库文件链接在一起,将每个符号对应到具体的内存地址,这时才需要确定函数或变量的地址;

所以extern关键字的作用就是在编译期告诉编译器,这个变量/函数是其他地方定义的,此时编译器也不需要直到具体是在哪里定义的,链接阶段会找到extern关键字修饰的变量/函数的真正地址
第二种情况,跨文件的extern,但是这里讲的是都是在c或者都是在c++文件之间的跨文件

都是在c或者都是在c++文件之间的跨文件都可以像下面这样使用,在一个源文件中extern另一个源文件中定义的内容;像上面讲的那样,编译期编译器只需要知道这些变量/函数是定义在其他地方的,链接的时候将extern_main.o和extern_other.o链接在一起,就可以找到这些变量/函数的具体地址

c 复制代码
// extern_main.c
int main() {

    extern int var_other;
    extern void func_other();

    func_other();
    printf("extern_main, var_other = %d\n", var_other);

    return 0;
}

// extern_other.c
int var_other = 99;

void func_other() {
    printf("func_other(), var_other = %d\n", var_other);
}

第三种情况,c++文件中extern c文件定义的内容

首先,要讲解一下c和c++的符号命名规则,在c语言中,编译器直接使用函数名作为符号名,比如在c文件中定义一个void foo();,编译后符号名还是foo;但是c++中因为支持函数重载、命名空间等特性,编译器会给函数名加上额外信息来区分,比如定义一个void foo(int);,编译后可能变成类似_Z3fooi,这就是所谓的名字修饰

所以如果直接在c++文件中使用extern引用c文件中定义的内容,c文件中有一个void print_hello();,c++中如果直接使用extern,链接时c++编译器实际找的符号可能是_Z11print_hellov这样的东西,但是c中的符号名和他不匹配,就会报错找不到定义

所以c++中引用c文件定义的内容需要使用extern "C",比如

cpp 复制代码
extern "C" void foo();
extern "C" {
    void print_hello();
}
extern "C" int global_var;

如果是在c++的头文件中引用c文件定义的变量/函数,一般是

c++ 复制代码
#ifdef __cplusplus
extern "C" {
#endif

void print_hello();
extern int g_count;

#ifdef __cplusplus
}
#endif
相关推荐
郝学胜-神的一滴2 分钟前
Qt 高级编程 045:坐标体系深度实战
开发语言·c++·windows·python·qt·程序人生
码匠许师傅11 分钟前
【设计模式精讲】22.中介者模式(Mediator)
c++·设计模式·软件工程·uml·中介者模式
dsyyyyy110120 分钟前
JS复习,难点,易错点总结
开发语言·javascript·ecmascript
策案案案35 分钟前
YOLO: 将AI Agents嵌入到IntelliJ IDEA
java·大数据·人工智能·笔记·yolo·microsoft·intellij-idea
HRTOS1 小时前
HRTOS 4.0 驱动库:06_Storage 存储设备驱动——24C02 EEPROM与I²C驱动开发
c语言·驱动开发·嵌入式硬件·51单片机
“AI国潮设计-小江”1 小时前
Python实战 | SDXL精准控制“普宁英歌舞×星空蛋糕”IP落地,附核心Prompt与商用授权思路
开发语言·人工智能·python·prompt·aigc
小刘在重生~3 小时前
Java常用类|String类详解 + BigDecimal精准计算(含面试题)
java·开发语言·python
爱吃巧克力的程序媛3 小时前
main.cpp注册 C++ 类到 QML 元对象系统
c++·qt
YYYing.3 小时前
【C++进阶系列 (二)】关于线程堆栈的那些事——函数调用过程
开发语言·c++·函数·线程堆栈
邪修king3 小时前
Re:Linux系统篇(十九):进程篇(八): 进程等待详解:wait/waitpid,僵尸进程到底该如何回收
java·开发语言