【C++】009、extern关键字

一、extern关键字设计的目的只有一个:那就是跨文件、跨语言地正确找到符号

  • 作为外部声明,告诉编译器变量或函数在别的文件里有定义,让编译器去别的目标文件找查看,先别急着报错。

  • 配合C语言使用(extern "C"),用于禁止C++的符号修饰(Name Mangling)功能,实现C和C++的混合编程

二、extern的基础使用

修饰变量或函数,只做声明,不定义

  • 本质:extern 关键字修饰的声明是承诺,而不是定义,它不分配内存,只是告诉编译器,这个符号(变量/函数)在其他编译单元(.cpp文件)中有定义,请链接时去哪里找。

  • 代码实现

cpp 复制代码
// FileA.cpp
int g_counter = 0;          // 定义(分配内存)
void logMessage() { ... }   // 定义

// FileB.cpp
extern int g_counter;       // 声明(不分配内存),告诉编译器去外部找
extern void logMessage();   // 声明(通常省略,函数默认就是extern的)

void test() {
    g_counter++;            // 链接时去 FileA.obj 找 g_counter
    logMessage();           // 链接时去 FileA.obj 找 logMessage
}

三、extern "C"的底层原理与使用场景

1、为什么需要设计出extern "C"?

  • 一句话总结:为了让C++兼容C,实现在C++程序中调用C语言函数库

  • C语言:符号名就是函数名,比如 void foo(int) 他的符号名就是 foo (注意C语言没有函数重载)

  • C++:支持函数重载,编译器会进行名字修饰,void foo(int) 会被修饰为 _Z3fooi, 在修饰后的符号名会标记参数信息

使用冲突:

  • 如果C++程序要调用一个C语言的库(.so, .a),默认链接时会去找 _Z3fooi,但C语言的库中只有foo,肯定找不到,会报链接错误(Undefined Reference)

2、extern "C"的标准写法

1)直接包裹单个函数

  • 在C++程序中调用C语言函数
cpp 复制代码
extern "C" {
    void c_function(int x);   // 告诉编译器:按 C 的规则去找这个函数
    int c_global_var;
}

2)兼容C/C++两种语言的双编译的头文件中调用extern

  • 既能让C++编译器识别,也能让C编译器识别

  • __cplusplus是C++编译器内置的宏

cpp 复制代码
// my_module.h
#ifdef __cplusplus
extern "C" {
#endif

// 这里是 C 语言接口声明(结构体、函数原型)
void init_module();
void process_data(int* data, int len);

#ifdef __cplusplus
}
#endif

3、类成员不能使用extern "C"

  • extern "C"只能修饰全局函数和全局变量

  • 不能作用域类成员函数,因为成员函数this指针和虚表(vtable),而C语言没有这两个概念

相关推荐
m0_547486661 小时前
《模式识别:使用MATLAB分析与实现》全套PPT课件
开发语言·matlab·模式识别
ShiXZ2131 小时前
PDF-OCR文件识别篇(七):数据入库
java·pdf·json·ocr·springboot
rebibabo2 小时前
Java基础(番外) | Kafka 入门:分区、副本与消费者组原理
java·分布式·kafka·学习笔记·副本·分区·异步日志
Flittly2 小时前
【AgentScope Java新手村系列】(17)长期记忆系统
java·spring boot·spring
wei1986212 小时前
.net添加web引用和添加服务引用有什么区别?
java·前端·.net
Full Stack Developme2 小时前
正则表达式的使用教程
java·数据库·正则表达式
zhiSiBuYu05172 小时前
重排序(Rerank)提升检索准确率实战指南
开发语言·python·算法