大意了,没有闪

起因是在VS新建了一个C++项目,然后试图引用一个用C写的函数库。结果编译运行的时候报错了,提示无法解析的外部符号。根据常识,这个问题一般与C++的函数重载有关,但是在仔细检查了库函数和调用时函数的签名之后发现并没有问题。用grepdumpbin对着编译出来的.lib静态库文件捣腾了老半天,也愣是没有找出问题所在。

左思右想,唯一的端倪在于用dumpbin观察.lib静态库文件时发现,编译出来的库函数是没有带C++后缀的,而报错的地方所调用的库函数是带了C++后缀的,这也正是导致出现函数名不匹配的地方。无奈之下只能去网上冲浪,带着我也描述不清的问题试图找出解决方法。

在万能的StackOverflow上看到了这个回答之后才意识到,函数名是在编译期确定的。由于头文件本身作为源文件参与编译,编译器只能通过源文件信息来确定这是C还是C++代码。很显然,.c后缀的被MSVC作为C代码编译,而.cpp文件则是作为C++代码编译。

而正是这细微的编译规则差异导致了本次的问题:在库函数源代码中,由于是以.c源文件的形式参与编译,遵循了C语言不允许函数重载的规则,编译出来的函数名就是头文件中所定义的函数名;而在我写的调用程序中,因为使用了.cpp格式的文件,代码使用了C++规则编译,因而给头文件中定义的函数名加上了C++的小尾巴(如@UAEXXZ这种)。在之后的链接过程中再用C++风格的函数名去匹配C风格的函数体,由于两者名字不一致,就产生了无法解析的外部符号问题。

解决方法也非常简单,在写C/C++混合调用的程序时,被调用者(主要是头文件)最好加上用#ifdef __cplusplus包装的extern "C"标记,以确保最大的兼容性

标签: none

添加新评论