extern "C" 浅析

用C++写了一个音视频解码器,调用了FFMPEG的动态链接库,并在代码里面包含了FFMPEG的头文件,如下:

#include "libswresample/swresample.h"
#include "libavutil/mem.h"
#include "libavutil/frame.h"
#include "libavutil/channel_layout.h"

修复了所有的编译语法错误后,最后卡在了几个链接错误上,其中的一处错误如下:

error LNK2019: unresolved external symbol "int __cdecl av_get_channel_layout_nb_channels(unsigned __int64)" (?av_get_channel_layout_nb_channels@@YAH_K@Z) referenced in function "public: void __cdecl AudioDec::init(void)" (?init@AudioDec@@QEAAXXZ)

查来查去,发现是C++和C的编译器不兼容,导致C++编译器无法链接到C的函数符号所致。下面我们来大概解释一下这个问题。

要解释清楚这个问题,需要来了解一下C++语言的符号修饰。

众所周知,C++语言强大而复杂,它拥有类、继承、重载、名称空间等特性,使得函数和变量等符号管理更加复杂,例如两个名字相同的函数int func(int)和float func(float),尽管两个函数名称相同,但是参数列表不同,属于C++重载中的一种情况,那么编译器和链接器在链接过程中如何区分这两个函数呢?这就用到了C++的名称修饰(Name Decoration)和名称改编(Name Mangling)。编译器和链接器在处理符号时,会使用某种符号修饰的方法,使得每个函数签名对应一个修饰后名称(Decorated Name)。C++的源代码编译之后形成的目标文件中,函数和变量所使用的符号名是原符号名经过修饰后的名称。C++编译器和链接器都使用符号名来识别和处理函数和变量,所以对于不同函数签名的函数,即使函数名相同,编译器和链接器都认为它们是不同的函数。

例如,对于前面例子中的 int func(int) 和float func(float)来说,在GCC编译器中,修饰后的名称分别是_Z4funci和_Z4funcf。不同编译器厂商的名称修饰方法不同,在Visual C++编译器中,以上两个函数修饰后的名称则是:?func@@YAHH@Z以及?func@@YAMM@Z。

有了以上的基本概念,我们就可以知道在音视频解码器编译时报错信息中红色部分的意思了(如下),分别是函数av_get_channel_layout_nb_channels()和AudioDec::init()经过修饰后的名称。

error LNK2019: unresolved external symbol "int __cdecl av_get_channel_layout_nb_channels(unsigned __int64)" (?av_get_channel_layout_nb_channels@@YAH_K@Z) referenced in function "public: void __cdecl AudioDec::init(void)" (?init@AudioDec@@QEAAXXZ)

以上是C++编译器对函数名的处理,而C编译器则没有这样复杂的修饰机制,我们所使用的FFMPEG库是C编译器编译的,因此如果不加声明,编译器会认为FFMPEG头文件中声明的函数是C++函数,因此将其按照C++编译器的符号修饰规则来修饰,这样链接器就无法链接到C语言库中相应的函数符号。因此,我们需要用extern "C"来声明包含的FFMPEG头文件为C语言文件,从而使用C编译和链接。因此,将本文最初的头文件包含语句修改如下后,编译通过。

extern "C"
{
	#include "libswresample/swresample.h"
	#include "libavutil/mem.h"
	#include "libavutil/frame.h"
	#include "libavutil/channel_layout.h"
};


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值