C和C++相互调用问题

引言

最近在开发wifi sdk,涉及到了C和C++之间的相互调用问题。刚开始有点云里雾里,搞明白之后,就比较清晰了。在此作为分享,希望以后少走弯路。

C++重载问题
开发的第一阶段,出现了一个问题,就是无法找到接口的符号表。每当加载libql_sdk.so时,就会如下错误:
在这里插入图片描述

代码环境:

ql_wifi.cpp
C和C++相互调用问题_第1张图片
C和C++相互调用问题_第2张图片

从报错内容上看,是找不到QL_API_LOGD的符号表。但是奇怪的是:QL_API_LOGD在mcli_common.h中声明了,并在mcli_common.c实现了,编译ql_sdk时,都会进行编译。按道理都在libql_sdk.so中,为什么会找不到呢?
C和C++相互调用问题_第3张图片

原因分析

这个问题其实就是GCC和G++汇编时,对接口命名的问题。GCC在建立符号表时,一般以接口的名字命名。但是C++支持重载,所以,g++在建立符号表时,会将函数的参数也放到代码中。
举个例子:
int add(int a,int b);
用GCC编译,在符号表中的符号应该add。如果是用g++编译,在符号表中的符号可能就是int_add_int_int。
这样我们就知道了,出现以上问题的原因就是由于,mcli_common.c使用的是GCC编译的。ql_wifi.cpp虽然引用了mcli_common.h头文件,但是使用g++编译。在汇编时,QL_API_LOGD的符号不一致。导致出现undefined symbol。

解决方式:extern “C”{}

我相信大家基本都会看到过 extern “C”的用法,但对它的作用可能不是很了解。
extern “C”,包含双重含义,从字面上可以知道,首先它修饰的目标是“extern“的;其次,被它修饰的目标代码是”C“的。
也就是被它修饰的目标,你应该用C语言的规则去编译(其中主要的就是需要编译器去按照C语言的规则去建立符号表)。
因此,我们最好的解决方式,就是在mcli_common.h中加上如下代码:
C和C++相互调用问题_第4张图片
表示,如果使用g++编译器,请将下面的目标按照C语言的方式建立符号表。因为它们的实现就是在mcli_common.c中,用C语言实现的。

拓展:C和C++相互调用的几种情况

C++调用C库

C++调用C库较为简单,由于C++是向前(向C)兼容的,很容进行调用。需要注意的是,在进行C库头文件包含的时候,使用
在这里插入图片描述
进行包含,指定g++用C的方式生成符号。

C调用C++库

C调用C++库,应该是我们常遇到的。我们linux侧的代码基本是C语言开发。有时会有C++的代码,一般有以下两种情况:

  1. C++开发的库
    我们有时需要利用一些已开发好的模块,而这些模块可能是C++写好的,我们直接引用,避免重复开发。
    a) 只提供给库文件和头文件
    若第三方,只提供给库和头文件,C是不能直接调用的。因为库
    中的符号表已经按照g++的语法建立。C语言包含头文件之后,按照C语言的语法进行连接,是找不到符号的。我们可以做一个中间接口库。对C++库进行二次封装:
    C和C++相互调用问题_第5张图片
    C文件直接调用中间接口库即可。
    b) 提供给了源码
    这种情况就较为简单了,将CPP文件中对外的接口,一致要求使用C语言的规则建立符号表即可。

你可能感兴趣的:(C语言,c++,linux,C语言,符号表)