extern 关键字

如何加载其他模块的全局变量? extern关键字

如何解决C++与C混合编译问题? extern “C”

extern关键字

声明与定义

根据C++标准的规定,一个变量声明必须同时满足两个条件,否则就是定义:

  1. 声明必须使用extern关键字;

  2. 不能给变量赋初值

1
2
3
4
int a;  //定义
int a = 0; //定义
extern int a =0; //定义
extern int a; //声明

使用其他模块变量例子

1
2
3
4
5
6
7
8
9
10
11
12
//file.h
extern int a;

//file.cpp
int a = 10;

//main.cpp
#include <cstdio>
#include "file.h"
int main(){
printf("a = %d", a);
}

终端上编译运行,输出

1
gcc main.cpp file.cpp && ./a.out

这等同于

1
2
3
4
5
6
7
8
9
//file.cpp
int a = 10;

//main.cpp
#include <cstdio>
extern int a;
int main(){
printf("a = %d", a);
}

如果不佳extern关键字将提示变量重复声明。

最佳实践

  • h文件extern声明
  • c/cpp文件内定义
  • 使用时include头文件

extern “C”

extern "C" 是 C++ 中的一个关键字组合,用于解决 C++ 和 C 代码混合编程时的 名称修饰(Name Mangling)链接兼容性 问题。它的核心作用是告诉 C++ 编译器:按 C 语言的规则处理函数名和链接方式,确保 C++ 代码可以正确调用 C 库函数,或者让 C 代码能调用 C++ 函数。

为什么需要这个关键字

知识点:C++与C的函数名称修饰规则不同

C++ 支持函数重载,编译器会对函数名进行修饰(例如 func(int) 可能变成 _Z4funci),以区分不同参数类型的同名函数。C 语言没有重载,函数名在编译后保持不变(例如 func 依然是 func)。如果 C++ 直接调用 C 库函数(或反过来),由于名称修饰差异,链接器会找不到符号,导致错误。

作用

  • 禁用名称修饰
    强制函数名按 C 语言的规则生成,保持简单名称。
  • 确保二进制兼容性
    使 C++ 编译后的函数符号与 C 库的符号一致,从而正确链接。

用法

(1) C++ 调用 C 函数

假设有一个 C 库 libfoo.c

1
2
3
4
5
// libfoo.c
#include <stdio.h>
void foo() {
printf("Hello from C!\n");
}

编译为 C 库:

1
gcc -c libfoo.c -o libfoo.o

在 C++ 中调用时,需要用 extern "C" 声明:

1
2
3
4
5
6
7
8
9
// main.cpp
extern "C" {
void foo(); // 告诉 C++ 编译器:foo 是 C 函数,不要修饰名称
}

int main() {
foo(); // 正确链接到 C 实现的 foo()
return 0;
}

编译链接:

1
g++ main.cpp libfoo.o -o program

(2) C 调用 C++ 函数

若要在 C 中调用 C++ 函数,需在 C++ 代码中用 extern "C" 导出函数:

1
2
3
4
5
6
// libbar.cpp
extern "C" {
void bar() { // 禁止名称修饰
std::cout << "Hello from C++!" << std::endl;
}
}

在 C 中声明:

1
2
3
4
5
6
7
// main.c
void bar(); // C 语言声明

int main() {
bar(); // 调用 C++ 实现的 bar()
return 0;
}

编译链接:

1
2
g++ -c libbar.cpp -o libbar.o
gcc main.c libbar.o -o program -lstdc++

应用场景

  1. 调用 C 标准库函数
    <stdio.h> 中的 printf 在 C++ 中通过 extern "C" 声明。

  2. 使用第三方 C 库
    例如 OpenSSL、SQLite 等 C 库的头文件通常包含 extern "C" 保护:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #ifdef __cplusplus
    extern "C" {
    #endif

    void c_library_function();

    #ifdef __cplusplus
    }
    #endif
  3. 导出 C++ 函数供 C 调用
    在编写 C++ 动态库(.so/.dll)时,需用 extern "C" 导出接口。

总结

场景 解决方案
C++ 调用 C 函数 extern "C" 声明 C 函数
C 调用 C++ 函数 extern "C" 定义 C++ 函数
头文件兼容 C/C++ 通过 #ifdef __cplusplus 包裹

仅适用于全局函数extern "C" 不能用于类成员函数或重载函数(因为 C 不支持这些特性)。

作者

Desirer

发布于

2025-05-20

更新于

2025-11-24

许可协议