@[TOC]
前言:
背景
- 在使用不同编程语言进行软件的开发时,需要统一变量,函数名等的链接规范。
- 如果C++项目中包含C静态库或者动态库,如果你直接包含C的库,那么因为C++的==内部名称修饰==和C的==内部名称修饰==是
不同的
,在程序的==链接环节==确定调用函数的==地址==就出问题了。当然C项目中包含C++库也会出现这种问题
C++编译器对标识符的修饰导致了,当链接时,去用修饰的标识符去C静态库查找时找不到的情况。C的标识 符是 _StackPush().
- 那么当如何解决呢?用C++特殊关键字 extern “C”.下面用程序来实现和这个过程。
内部名称修饰
extern “C”
- extern ”C“ C++编译器可以识别而C编译器不可以识别,这也是C++项目包含C库和 C项目包含C++项目的有些地方不同。
- extern “C”会告诉编译器,所包含的内容在 ==链接确定调用函数地址时== 要用 C规则(标识符前加一个 “_”)改变标识符的内部名称。》》这个地方可以理解为 编译器在编译时遇到extern “C”时就对其包含的标识符进行的标记 ,这样在链接调用时就能知道那些标识符该修改了。
- extern “C” 可以对某一个函数进行修饰,也可以对一段代码修饰。
extern "C" void fun(); extern "C" void swap(); extern "C" { void fun(); void swap(); }
C++项目调用C静态库
C静态库的生成
这里我用栈的2个文件 stack.cpp和stack.h
C++项目中C静态库的包含于配置、
包含
配置一
配置二
效果
C项目调用C++库
C++静态库的生成
- 因为==C无法识别extern ”C"==,因此需要在==C++库==中进行部分修饰。
- 修饰的目的是,在C++库中使用C编译器,这样C++库中标识符就是用C修饰的内部名称,在C项目链接这个库时,就不用担心链接问题—C++库中的标识符是C的标识符。
- 这里用预处理指令来处理程序。
这里也需要C++库文件进行修饰,否则C项目包含C++库时是无法C++函数库的
#ifdef __cplusolus #include<iostream> using namespace std; #endif // __cplusolus
一种思考是:用extern “c”包含所有要用C编译器处理的代码。
//方式一: #ifdef __cplusplus extern "C" { #endif void StackInit(stack * s);//初始化 void StackPush(stack * s, SDateType x);//入栈 注意sz始终指向入完元素后的下一个位置 void StackPop(stack * s);//出栈 只需要sz--就行 1.数据可以被覆盖 2.动态开辟的连续内存不允许在中间任何地方free void StackPrint(stack * s);//打印 void StackDestroy(stack * s);//销毁 SDateType StackTop(stack * s);//取栈顶元素 bool StackEmpty(stack * s);//判断是否为空,因为sz的特殊性,当sz为0,代表栈空 获取栈中有效元素个数 int StackSize(stack * ps); #ifdef __cplusplus } #endif
另外一种是在每条指令前加extern “C”
#ifdef __cplusplus #define EXTERN_C extern "C" #else #define EXTERN_C #endif EXTERN_C void StackInit(stack* s);//初始化 EXTERN_C void StackPush(stack* s, SDateType x);//入栈 //注意sz始终指向入完元素后的下一个位置 EXTERN_C void StackPop(stack* s);//出栈 //只需要sz--就行 //1.数据可以被覆盖 //2.动态开辟的连续内存不允许在中间任何地方free EXTERN_C void StackPrint(stack* s);//打印 EXTERN_C void StackDestroy(stack* s);//销毁 EXTERN_C SDateType StackTop(stack* s);//取栈顶元素 EXTERN_C bool StackEmpty(stack* s);//判断是否为空,因为sz的特殊性,当sz为0,代表栈空 // 获取栈中有效元素个数 EXTERN_C int StackSize(stack* ps);
效果
总结
- 再次感叹提出内部名称修修的神奇。一个修饰解决了很多的问题,编译问题,链接问题,不同模块间的连接规范。
- 通过连接规范,只给含义机器码的库文件就不用担心源码的流出。