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

简介:

@[TOC]

前言:

  • 本文介绍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

总结

  • 再次感叹提出内部名称修修的神奇。一个修饰解决了很多的问题,编译问题,链接问题,不同模块间的连接规范。
  • 通过连接规范,只给含义机器码的库文件就不用担心源码的流出。
相关文章
|
6天前
|
安全 编译器 程序员
【C++初阶】C++简单入门
【C++初阶】C++简单入门
|
1月前
|
程序员 C++
C++模板元编程入门
【7月更文挑战第9天】C++模板元编程是一项强大而复杂的技术,它允许程序员在编译时进行复杂的计算和操作,从而提高了程序的性能和灵活性。然而,模板元编程的复杂性和抽象性也使其难以掌握和应用。通过本文的介绍,希望能够帮助你初步了解C++模板元编程的基本概念和技术要点,为进一步深入学习和应用打下坚实的基础。在实际开发中,合理运用模板元编程技术,可以极大地提升程序的性能和可维护性。
|
2月前
|
消息中间件 存储 开发工具
消息队列 MQ产品使用合集之C++如何使用Paho MQTT库进行连接、发布和订阅消息
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
|
11天前
|
安全 编译器 C++
C++入门 | 函数重载、引用、内联函数
C++入门 | 函数重载、引用、内联函数
18 5
|
11天前
|
存储 安全 编译器
C++入门 | auto关键字、范围for、指针空值nullptr
C++入门 | auto关键字、范围for、指针空值nullptr
32 4
|
11天前
|
编译器 C语言 C++
C++入门 | 命名空间、输入输出、缺省参数
C++入门 | 命名空间、输入输出、缺省参数
25 4
|
11天前
|
编译器 程序员 C语言
C++入门
C++入门
22 5
|
4天前
|
安全 编译器 C语言
|
5天前
|
存储 编译器 程序员
C++从遗忘到入门
本文主要面向的是曾经学过、了解过C++的同学,旨在帮助这些同学唤醒C++的记忆,提升下自身的技术储备。如果之前完全没接触过C++,也可以整体了解下这门语言。
|
1月前
|
存储 安全 编译器
【C++入门 四】学习C++内联函数 | auto关键字 | 基于范围的for循环(C++11) | 指针空值nullptr(C++11)
【C++入门 四】学习C++内联函数 | auto关键字 | 基于范围的for循环(C++11) | 指针空值nullptr(C++11)