C++代码中使用extern "C"的原因

C++代码中externC{}

我们经常在C++代码中看到下面的代码:

#ifdef __cplusplus
    extern "C" {
		int func();
	}
#endif

我们知道__cplusplus是c++编译器预定义的宏,上面这段代码只要有在使用C++编译器进行代码编译的时候,才会起作用。


那么,extern "C" { }是做什么的呢?

在回到这个问题之前,需要了解“函数调用约定”:

常见的函数调用约定有四种:cdecl、stdcall、fastcall、thiscall。他们在函数参数压栈顺序、堆栈恢复和函数名等方面有差别:

调用方式参数压栈方式恢复堆栈函数名备注
stdcall参数从右向左压入堆栈函数自身修改堆栈函数名自动加前导的下划线,后面紧跟一个@符号,其后紧跟着参数的尺寸被称为pascal调用
cdecl参数从右向左压入堆栈调用者负责清理堆栈自动在函数名前加前导的下划线C语言缺省的调用约定,支持可变参数
fastcall第一个和第二个DWORD参数(或者尺寸更小的)通过ecx和edx传递,其他参数通过从右向左的顺序压栈函数自身修改堆栈函数名自动加前导的下划线,后面紧跟一个@符号,其后紧跟着参数的尺寸除了前面两个参数压栈方式,其他和stdcall相同
thiscall参数从右向左压入堆栈,如果参数个数确定,this指针通过ecx传递给被调用者;如果参数个数不确定,this指针在所有参数压栈后被压入堆栈参数个数不定的,调用者清理堆栈,否则函数自己清理堆栈仅适用于C++C++类成员函数缺省的调用约定
注意:不同的调用约定,编译器会对函数名进行修改,如函数int func(int a,int b),使用cdecl调用是,函数名被修改为_func,而stdcall调用时,函数名被修改为_func@8。

C语言默认使用cdecl,VC 中默认调用是 cdecl 方式,而Windows API 使用 stdcall 调用方式,这样就会导致链接时出现函数名找不到的情况。

extern "C" { }表示{}中的代码使用C语言的方式进行编译和链接。这样,全部都是用cdecl调用约定,在C和C++混编的时候,就不会出现链接时找不到函数定义的问题。


在 C 和 C++ 中,`extern` 关键字用于指定变量或函数的链接属性,即它们的可见性和生命周期。尽管两者共享 `extern` 的基本概念,但在具体使用方式和语义上存在一些关键区别。 ### 声明全局变量 在 C 语言中,`extern` 主要用于声明全局变量,这些变量可以在多个源文件之间共享。例如: ```c // file1.c int globalVar = 10; // file2.c extern int globalVar; ``` 在 C++ 中,`extern` 同样可以用来声明全局变量,但通常推荐使用命名空间来组织代码,以提高可读性和避免名称冲突。 ```cpp // file1.cpp namespace MyNamespace { int globalVar = 10; } // file2.cpp namespace MyNamespace { extern int globalVar; } ``` ### 声明函数 对于函数而言,在 C 语言中,函数默认具有外部链接性,因此不需要显式地使用 `extern` 来声明函数原型。然而,在某些情况下,如需要从汇编代码中调用 C 函数时,可能会使用 `extern` 来声明这些函数。 在 C++ 中,除了声明函数外,`extern "C"` 是一个特殊的构造,它告诉编译器按照 C 的规则来处理函数名,这样可以防止名称修饰(name mangling),使得 C++ 编写的函数能够被 C 代码调用。 ```cpp extern "C" void myFunction() { // 函数体 } ``` ### 使 const 变量具备外部连接性 在 C++ 中,常量 (`const`) 默认具有内部链接性,这意味着它们只能在定义它们的文件内部访问。为了使 `const` 变量能够在多个文件间共享,必须显式地使用 `extern` 关键字。 ```cpp // header.h extern const int MaxValue; // implementation.cpp const int MaxValue = 100; ``` 而在 C 语言中,由于没有 `const` 关键字的这种特性,所以通常直接声明为 `extern` 即可。 ### 注意事项 - 在使用 `extern` 时,重要的是确保变量或函数的实际定义只出现一次,否则会导致链接错误。 - 使用 `extern "C"` 时需要注意,它仅适用于 C++ 代码,并且应该包裹在条件预处理器指令中,以便头文件可以同时被 C 和 C++ 文件包含 [^3]。 ### 总结 虽然 `extern` 在 C 和 C++ 中都用于控制符号的链接属性,但是 C++ 提供了更多的功能,比如 `extern "C"` 来支持与 C 的互操作性。此外,C++ 推荐使用命名空间而不是全局变量来管理跨文件的数据共享 [^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值