作者介绍:
关于作者:东条希尔薇,一名喜欢编程的在校大学生
主攻方向:c++和linux
码云主页点我
本系列仓库直通车
作者CSDN主页地址
本篇文章的代码我将会上传到我的gitee上
我们在实际工作中,可能会遇到以下这种情景:
假如有两家互联网公司,他们互相为竞争对手
恰巧又在这个时候,A公司这个时候写出了一段代码,这段代码内部的内容对B公司的发展有特别大的作用
B公司又特别想要,A公司但是并不想把代码的核心内容透露给B公司
又转念一想,我们倒不如让B公司先用着这个代码,钱该赚就赚,但是绝对不能透露代码的半点细节,那该怎么办?
答案是:加密!
没错,是加密,不过是让计算机帮我们加密,把一段代码打包成可执行的.lib或.dll,静态库,动态库。这样它就可以运行起来,但是内部的代码却已经转成了机器语言(而二进制代码)人类是无法看懂机器语言的
使用者只需要包含静态库对应的头文件就可以使用这个编译好的静态库了
知识补充:静态库是指在我们的应用中,有一些公共代码是需要反复使用,就把这些代码编译为“库”文件;在链接步骤中,连接器将从库文件取得所需的代码,复制到生成的可执行文件中的这种库。
但是有个问题是我们这篇文章需要讨论的,
我的项目是c++的,能不能使用c编译的静态库?
或者,我的项目是c的,能不能使用c++编译的静态库?
就要用到extern c这个语句了
现在开始介绍extern c在不同场景下的用法
本文使用lib来解释extern c的用法
有时候在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加extern “C”,意思是告诉编译器,将该函数按照C语言规则来编译。
比如:tcmalloc是google用C++实现的一个项目,他提供tcmallc()和tcfree
两个接口来使用,但如果是C项目就没办法使用,那么他就使用extern “C”来解决。
所以,我们可以知道,extern c只能在c++文件中使用
如果我们要使用c的风格来编写函数,在c++中使用,不用extern c会有什么后果?
我们可以先来学习一下编译和调用lib文件
首先我们可以先编写好一个lib文件,我们这边假如要用栈这个数据结构
#include "pch.h" #include "framework.h" #include "Stack.h" void StackInit(ST* ps) { assert(ps); ps->a = malloc(sizeof(STDataType) * 4); if (ps->a == NULL) { printf("failn"); exit(-1); } ps->capacity = 4; //初始top为0,意味着top指向的是栈顶元素的下一个 ps->top = 0; } void StackDestory(ST* ps) { assert(ps); free(ps->a); ps->a = NULL; ps->top = ps->capacity = 0; } void StackPush(ST* ps, STDataType x) { assert(ps); if (ps->top == ps->capacity) { STDataType* tmp = (STDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(STDataType)); if (tmp == NULL) { printf("failn"); exit(-1); } else { ps->a = tmp; ps->capacity *= 2; } } ps->a[ps->top] = x; ps->top++; } void StackPop(ST* ps) { assert(ps); assert(ps->top); ps->top--; } STDataType StackTop(ST* ps) { assert(ps); assert(ps->top); return ps->a[ps->top - 1]; } int StackSize(ST* ps) { assert(ps); return ps->top; } bool StackEmpty(ST* ps) { assert(ps); return ps->top == 0; }
项目截图
注意:上面的pch和stack的文件格式必须保持一致,不然会编译错误
我们只需要使用编译,让其编译完成
这样我们的文件中就出现了这样的lib文件
我们要在项目中使用这个静态库还需要以下三个步骤:
-
包含库的头文件
-
添加附加库目录
-
添加附加依赖项
我们的库就配置完成了
这里是我们的测试代码:
#include"../../Stack/Stack/Stack.h" #includeusing namespace std; int main() { ST st; StackInit(&st); StackPush(&st, 1); StackPush(&st, 2); StackPush(&st, 3); StackPush(&st, 4); StackPush(&st, 5); cout << StackTop(&st) << endl; StackPop(&st); cout << StackTop(&st) << endl; return 0; }
但是我们却仍然不能使用
这里是报的链接错误,就说明我们在调用函数的时候编译器找不到函数的位置
结合我们上篇文章的内容我们很快就能发现原因:我们c和c++的函数修饰规则是不一样的,所以c和c++的编译模式是不通用的
那么,如何让c++和c之间能够顺利运行呢?
在c++项目中使用c编译的静态库这个很简单,我们只需要在头文件处(或者函数声明处)加入extern "C"即可
extern "C" { #include"../../Stack/Stack/Stack.h" }
这样我们的项目就变成了
#includeusing namespace std; extern "C" { #include"../../Stack/Stack/Stack.h" } int main() { ST st; StackInit(&st); StackPush(&st, 1); StackPush(&st, 2); StackPush(&st, 3); StackPush(&st, 4); StackPush(&st, 5); cout << StackTop(&st) << endl; StackPop(&st); cout << StackTop(&st) << endl; return 0; }
这样的工程是能够正常使用的
在c项目中使用c++的静态库这里我们就不能使用上面的代码了
因为extern c这个语句只能在c++中使用,c编译器是不认识这个指令的
所以我们在这种情况下,需要在c++库中动点手脚
我们这里需要用到条件编译的知识:
知识补充:__cplusplus只有在c++文件中才能正常使用
所以我们在库的头文件这里可以使用这段代码:
//Stack.h #ifdef __cplusplus extern"C" { #endif void StackInit(ST* ps); void StackDestory(ST* ps); void StackPush(ST* ps, STDataType x); void StackPop(ST* ps); STDataType StackTop(ST* ps); int StackSize(ST* ps); bool StackEmpty(ST* ps); #ifdef __cplusplus } #endif
对代码的几点解释:
如果在库中的文件要使用这个头文件,代码就是原样
如果在c项目中,extern c被条件编译屏蔽掉了,就是这个样子
#ifdef __cplusplus //extern"C" //{ //#endif void StackInit(ST* ps); void StackDestory(ST* ps); void StackPush(ST* ps, STDataType x); void StackPop(ST* ps); STDataType StackTop(ST* ps); int StackSize(ST* ps); bool StackEmpty(ST* ps); //#ifdef __cplusplus //} //#endif
就是普普通通的一段定义,就可以直接使用了
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)