【C++】vs2019建立静态库 + extern “C“ 的实例详解
使用场景
我们在C++中需要调用C的库时会需要使用 extern "C"
1.C++调用C
我们以leetcode20.有效的括号为例,答案点这里,这道题我们用C写了一个栈的函数库方便调用。
1.我们将main函数以及题目提供的接口函数放置在C++的工程文件test1的源文件test.cpp中:
//test.cpp
bool isValid(char* s)
{}
int main()
{}
2.我们将栈的函数制成C的静态库
用到栈的函数
栈函数的编写见这里。
3.然后按f7键对这个静态库进行编译,随后会在DS目录的debug文件夹中找到相应的lib文件。
4.然后在C++中调用C的
静态库头文件
注意这里调用的方式
../
——表示寻回上一层文件
再对C++工程文件进行设置:
a.附加库目录(DS下的Debug文件
):
b.附加依赖项:DS.lib;
(不要漏掉分号)
这时,我们按下f7进行编译,发生报错:
由于C和C++对函数名修饰规则的不一致
,导致C++无法在C静态库找到中对应名字的函数,使用不了C编译的静态库。
5.这时
extern "C"
派上用处了!
用法如下↓
这时再编译test.c
调用成功!
2.C调用C++
当我们编写C语言需要使用C++库时,同样可以使用extern "C"
1.C文件放main函数和接口函数
2.建立C++静态库存放栈函数并编译产生lib文件,与上面一致,这里不再赘述
3.我们继续在C文件中写上调用,并且对
附加库目录
和附加依赖项
进行设置,然后先按f7试下能否调用
报错
c++中的函数名是被修饰的,C文件对其进行调用依然因为函数名修饰的规则不同
,而找不到相应的函数。
4.这里我们同样可以利用
extern "C"
, 使C++静态库以C的函数名修饰规则去处理函数
,从而让C文件识别出这些函数并顺利调用。
由于C++静态库的头文件预处理后在C的工程文件下展开,而C的语法规则中不包含extern "C"
,
我们就做一些小小的改变,使C++静态库以C的函数名修饰规则去处理栈函数,又可以让C在调用时避开extern “C”——条件编译
。
条件编译的第一种方法
:
#ifdef __cplusplus
extern "C"
{
#endif
//初始化栈
void StackInit(ST * ps);
//销毁栈
void StackDestroy(ST* ps);
void StackPush(ST* ps, STDataType x);//压栈
void StackPop(ST* ps);//弹栈
//当前栈的大小
int StackSize(ST* ps);
//获取栈顶元素
STDataType StackTop(ST* ps);
//栈是否为空
bool StackEmpty(ST* ps);
#ifdef __cplusplus
}
#endif
解释
:第一次编译时是C++静态库建立的过程,在C++文件下编译,__cplusplus处于激活状态(__cplusplus的值是为了表示C++的版本),可以使用extern "C"
对C++静态库以C的函数名修饰规则去处理函数
,随后生成lib文件。
第二次编译时已在C工程环境下,__cpluscplus没有定义,可以跳过extern "C"
,所以C可以直接调用这些符合C函数命名规则的函数了。
条件编译的第二种方法
:
#ifdef __cplusplus
#define EXTERN_C extern "C"//以C的命名规则去修饰函数
#else
#define EXTERN_C
#endif
//初始化栈
EXTERN_C void StackInit(ST* ps);
//销毁栈
EXTERN_C void StackDestroy(ST* ps);
EXTERN_C void StackPush(ST* ps, STDataType x);//压栈
EXTERN_C void StackPop(ST* ps);//弹栈
//当前栈的大小
EXTERN_C int StackSize(ST* ps);
//获取栈顶元素
EXTERN_C STDataType StackTop(ST* ps);
//栈是否为空
EXTERN_C bool StackEmpty(ST* ps);
C++文件按f7重新编译生成lib后,再对C文件运行
调用成功
总结
1.C++调用C的库
在C++程序调用的库前添加extern "C"
设置附加库目录
和附加依赖项
,可链接到C静态库。
2.C调用C++的库
在C++库中加extern "C" (条件编译)
进行编译生成lib,
在C中可直接调用C++静态库
源代码戳这里
青山不改 绿水长流