1.C++和C生成的符号信息不一样
C++在语法上是兼容C的,但是这不代表使用C语言不做任何处理直接写成的动态链接库就可以被C++给调用。由于C++引入了函数重载的机制,而这个机制的实现是在编译器层面的。编译器在“生成”函数符号信息时,不能仅仅通过函数名,因为重载函数的函数名都是一样的,所以它还要根据函数参数,命名空间等信息来确定唯一的函数签名;而C语言没有函数重载机制,C语言编译器在处理的时候通过函数名就可以唯一确定一个函数。这就导致C语言和C++语言生成的函数签名是不同的,故不能不做任何处理直接调用。下面我们来看一下C和C++编译同样一段代码为动态链接库以后的,它们的函数符号信息有什么不一样。
#include<stdio.h>
void Print_HelloWorld()
{
printf("Hello World!\n");
}
保存这段代码为两份,分别是helloworld_c.c和helloworld_cpp.cpp。下面编译它们为动态链接库。
下面使用nm命令来查看生成的函数符号信息。
可以看到gcc和g++生成的函数符号信息是不同的,因此,不做任何处理肯定是不能直接调用的。这里使用nm命令可以查看符号信息是因为我们没有给这两个动态链接库进行“瘦身”。在实际开发和应用中,你的动态链接库应该先进行“瘦身”。命令如下:
进行“瘦身”以后,符号信息等就被处理掉了,动态链接库的体积也会相应的减少。我们就无法通过nm查看了,如下所示。
2.如何使C++能调用C动态链接库
C语言提供了extern "C"来使得C++能够调用C。例子如下所示:
helloworld_c.h文件
#ifndef HELLOWORLD_C_H
#define HELLOWORLD_C_H
#include <stdio.h>
#ifdef __cplusplus //使用__cplusplus宏配合extern "C"来告诉C++链接器,这是一个C接口。
extern "C"{
#endif
void Print_HelloWorld();
#ifdef __cplusplus
}
#endif
#endif //HELLOWORLD_C_H
helloworld_c.c文件
#include"helloworld_c.h"
void Print_HelloWorld()
{
printf("Hello World!\n");
}
main.cpp文件
#include"helloworld_c.h"
int main()
{
Print_HelloWorld();
return 0;
}
首先,我们把helloworld_c.c文件编译为动态链接库,名为lib_helloworld_c.so
然后,把这个动态链接库拷贝一份到/usr/lib下面即可。
最后,编译main.cpp文件。编译的时候需要链接动态链接库,编译命令如下:
g++ main.cpp -o main -L. -l_helloworld_c
这样就会生成一个名为main的可执行文件。./main执行之后就会看到输出如下: