C++入门>>连接规范---extern “C“

前言:

  • 本文介绍C++程序中的连接规范》》extern “C”

  • 博主收集的资料New Young,连载中。

  • 博主收录的问题:New Young

  • 转载请标明出处:New Young

背景

  • 在使用不同编程语言进行软件的开发时,需要统一变量,函数名等的链接规范。

  • 如果C++项目中包含C静态库或者动态库,如果你直接包含C的库,那么因为C++的内部名称修饰和C的内部名称修饰不同的,在程序的链接环节确定调用函数的地址就出问题了。当然C项目中包含C++库也会出现这种问题

image-20220317221758341

C++编译器对标识符的修饰导致了,当链接时,去用修饰的标识符去C静态库查找时找不到的情况。C的标识 符是 _StackPush().

  • 那么当如何解决呢?用C++特殊关键字 extern “C”.下面用程序来实现和这个过程。

内部名称修饰

image-20220317212123482

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

image-20220317215007851

C++项目中C静态库的包含于配置、

包含

image-20220317221557375

配置一

image-20220317223758825

配置二

image-20220317223957195

效果

image-20220317224243207

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);
    
    

image-20220318105051591

效果

image-20220318105446238

总结

  • 再次感叹提出内部名称修修的神奇。一个修饰解决了很多的问题,编译问题,链接问题,不同模块间的连接规范。
  • 通过连接规范,只给含义机器码的库文件就不用担心源码的流出。

猜你喜欢

转载自blog.csdn.net/qq_55439426/article/details/123569659