卡码笔记
首页
计算机基础
C++
Java
面经
笔记广场 (opens new window)
代码随想录 (opens new window)
首页
计算机基础
C++
Java
面经
笔记广场 (opens new window)
代码随想录 (opens new window)
  • 基础与语法

    • 介绍c++一下三大特性
    • 指针和引用的区别
    • 结构体和类的区别
    • 结构体与联合体的区别
    • static关键字和const关键字的作用
    • extern C的作用
      • 简要回答
      • 详细回答
      • 代码示例
      • 知识拓展
    • volatile关键字的作用
    • inline函数与宏的区别与优劣
    • auto和decltype的区别
    • sizeof和strlen的区别
    • 浮点数比较方法
    • 静态局部变量,全局变量,局部变量的特点,以及使用场景
    • C++中四种类型转换
  • 面向对象

  • STL 与容器

  • 内存管理

  • C++11 与现代 C++

  • 智能指针

  • 并发与 I/O

# extern "C"的作用

# 简要回答

extern "C" 是 C++ 编译器提供的一个链接规范(Linkage Specification),其主要作用是指示编译器按照 C 语言的规则来编译和链接其修饰的代码。

这主要体现在函数名修饰(Name Mangling)和调用约定(Calling Convention)上,目的是为了解决 C++ 与 C 以及其他语言在混合编程时的链接兼容性问题。

简单点说: extern "C" 用于告诉 C++ 编译器,被它修饰的函数或变量应使用 C 语言的编译和链接规则,即不进行名称修饰(Name Mangling),从而确保 C++ 代码可以正确链接到用 C 语言编译的库或目标代码。

# 详细回答

核心问题:**名称修饰 **(Name Mangling)

C++ 支持函数重载(Overloading),即多个函数可以有相同的名字但不同的参数列表。

为了在编译后的二进制代码中区分这些函数,编译器会对函数名进行复杂的修饰(Mangling),将参数类型、返回类型等信息编码到一个新的、唯一的内部名称中。

举例子,函数 void foo(int) 可能被修饰为 _Z3fooi。

C 语言不支持重载,因此没有名称修饰。

函数 void foo(int) 在编译后的符号表中名字仍然是简单的 foo。

这是链接时就会出现困境

当一个 C++ 程序(main.cpp)试图调用一个由 C 编译器编译的库(c_lib.a)中的函数 foo 时,会发生以下情况:

C++ 编译器在 main.cpp 中看到 foo(...),会对其进行名称修饰(例如,生成_Z3fooi )。

但在链接阶段,链接器会在 C 编译的库中**寻找符号 _Z3fooi **。

而 C 库中导出的符号名是未修饰的 foo。

结果:链接器找不到 _Z3fooi,报“undefined reference”错误。

extern "C" 的解决方案 通过在 C++ 代码中使用 extern "C" 来声明 C 库中的头文件,明确指示编译器:“请不要对这里面的函数名进行修饰,直接使用原始的 C 风格名称。”

这样,C++ 编译器生成的目标文件中寻找的符号名就是 foo,从而能与 C 库中的 foo 符号成功链接。

调用约定 (Calling Convention) 除了名称修饰,extern "C" 通常也意味着使用 C 语言的调用约定(如 __cdecl),这规定了函数参数如何压栈、栈由谁清理等底层细节,确保了二进制层面的兼容。

# 代码示例

// In my_class.h (C++ header)
class MyClass {
public:
    int doSomethingComplex(int x);
};

// In c_interface.h (C-compatible header)
#ifdef __cplusplus
extern "C" {
#endif
int c_wrapper_do_something(int x);
#ifdef __cplusplus
}
#endif

// In c_interface.cpp
#include "my_class.h"
#include "c_interface.h"

extern "C" int c_wrapper_do_something(int x) {
    MyClass obj; // 在C++内部使用类
    return obj.doSomethingComplex(x); // 调用成员函数
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 知识拓展

  • 知识图解

image

  • 适用场景:

case1:调用 C 语言库:这是最经典的场景,如调用 Linux 的系统 API(glibc)、第三方 C 库(SQLite, Lua, libpng 等)。

case2:C++ 实现被 C 调用:如果你想用 C++ 写一个库,并希望它能被 C 程序调用,也需要在 C++ 的实现文件里用 extern "C" 来导出函数。

case3:与其它语言交互:许多脚本语言(如 Python、Lua)的解释器是用 C 编写的,它们的扩展接口(FFI)通常是 C 风格的。用 C++ 写这些扩展时,必须使用 extern "C" 来导出初始化函数,才能被宿主语言正确识别和加载。

Last Updated: 3/10/2026, 6:08:48 PM

← static关键字和const关键字的作用 volatile关键字的作用 →

评论

验证登录状态...

侧边栏
夜间
卡码简历
代码随想录
卡码投递表🔥
2026群
添加客服微信 PS:通过微信后,请发送姓名-学校-年级-2026实习/校招
支持卡码笔记
鼓励/支持/赞赏Carl
1. 如果感觉本站对你很有帮助,也可以请Carl喝杯奶茶,金额大小不重要,心意已经收下
2. 希望大家都能梦想成真,有好的前程,加油💪