c++调用c函数必须用extern "c"声明以避免名称重整;数组参数在混编中退化为指针,需显式传size;动态内存须同侧分配释放,推荐统一用malloc/free。

函数声明必须用 extern "C" 包裹
不加 extern "C",C++ 编译器会对函数名做名称重整(name mangling),比如 process_array 可能变成 _Z13process_arrayPii,而 C 编译器只认原始符号名,链接时直接报 undefined reference。
正确写法是:
// 在头文件中(同时供 C 和 C++ 使用)
#ifdef __cplusplus
extern "C" {
#endif
<p>void process_array(int* arr, int size);</p><h1>ifdef __cplusplus</h1><p>}</p><h1>endif</h1><p></p>
- 不能只在定义处加
extern "C",调用方看不到声明也会出错 - 如果头文件被 C 文件包含,
__cplusplus宏未定义,extern "C"块会被跳过,安全 - 不要在函数体内或局部作用域写
extern "C",它只对函数声明/定义起作用
int arr[] 和 int* arr 在混编中完全等价
C 和 C++ 都规定:函数形参中 int arr[] 会自动退化为 int*,编译器根本不检查方括号里的数字(哪怕写了 int arr[10] 也毫无约束力)。所以混编时别指望靠这个做类型保护。
- C 文件里写
void f(int a[]),C++ 文件里写void f(int* a),只要签名一致就能链接成功 - 但二者都丢失长度信息——你必须显式传
size参数,否则 C 端无法知道数组边界 - 不要在 C++ 端用数组引用(如
int (&arr)[5])传给 C 函数,C 不支持引用类型,链接直接失败
数组大小必须由调用方计算并传入
C 语言没有 std::size 或 std::extent_v,也没有运行时类型信息。栈数组的长度只能靠 sizeof(arr)/sizeof(arr[0]) 在定义处算,且仅对本地定义的数组有效。
- 若数组来自
malloc或全局变量,sizeof会返回指针大小(通常是 4 或 8),不是元素个数 - C++ 端若用
std::vector,必须用v.data()+v.size()转成 C 兼容接口,不能直接传&v[0]而不传 size - 常见错误:C 函数里用
while (*arr) { ... }假设数组以 0 结尾——这仅适用于字符串,对普通整数数组极危险
动态分配数组的生命周期必须由同一侧管理
谁 malloc,谁 free;谁 new[],谁 delete[]。跨语言释放是未定义行为,轻则崩溃,重则内存破坏。
- C++ 端分配、C 端使用:可以,只要 C 函数只读/只写,不
free - C 端分配(
malloc)、C++ 端释放(delete[]):绝对禁止 - 如果 C 接口设计成要求调用方释放,C++ 端必须用
free,而不是delete - 建议统一用
malloc/free在混编边界交互,避免 new/delete 和 malloc/free 混用
混编时最容易被忽略的其实是数组边界的“信任链”:C 端完全依赖 C++ 调用方传入的 size 值,没有任何校验手段。一旦传错,越界访问就发生在 C 代码里——而 C 的调试信息比 C++ 更难追溯。
13万字C语言保姆级教程(深入):立即使用
在学习笔记中,你将探索c语言的核心概念和高级技巧!











