【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语言没有这两个概念

相关推荐
小羊没烦恼!3 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
俊昭喜喜里3 天前
java中的继承和多态的区别
java
小羊没烦恼!3 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
譕痕3 天前
JSONObject与JSONArray封装数据格式区别
java·json
胡写代码3 天前
别再前后端各写一套表单校验了
java·后端
小鱼能吃糖3 天前
缺陷修复总览 · mall电商项目:5类缺陷,1个病根,4个业务域
java·电商
此时不提桶,更待何时3 天前
01-06-A-JVM排查实战详解
java·jvm
伞伞悦读3 天前
【第38期】Python 模块与包详解:import、from、模块搜索路径、包结构和 __init__
开发语言·python
vipxieliang3 天前
ValidX 在 DDD 领域驱动设计中的实践
java·spring boot
C语言小火车3 天前
C/C++ 为什么需要编译器?
开发语言·c++