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

总结

  • 再次感叹提出内部名称修修的神奇。一个修饰解决了很多的问题,编译问题,链接问题,不同模块间的连接规范。
  • 通过连接规范,只给含义机器码的库文件就不用担心源码的流出。
相关文章
|
1月前
|
编译器 C++
C++入门12——详解多态1
C++入门12——详解多态1
38 2
C++入门12——详解多态1
|
1月前
|
编译器 C语言 C++
C++入门3——类与对象2-2(类的6个默认成员函数)
C++入门3——类与对象2-2(类的6个默认成员函数)
23 3
|
1月前
|
存储 编译器 C语言
C++入门2——类与对象1(类的定义和this指针)
C++入门2——类与对象1(类的定义和this指针)
29 2
|
1月前
|
C++
C++入门13——详解多态2
C++入门13——详解多态2
79 1
|
1月前
|
程序员 C语言 C++
C++入门5——C/C++动态内存管理(new与delete)
C++入门5——C/C++动态内存管理(new与delete)
66 1
|
1月前
|
编译器 C语言 C++
C++入门4——类与对象3-1(构造函数的类型转换和友元详解)
C++入门4——类与对象3-1(构造函数的类型转换和友元详解)
19 1
|
1月前
|
存储 编译器 C++
C++入门3——类与对象2-1(类的6个默认成员函数)
C++入门3——类与对象2-1(类的6个默认成员函数)
30 1
|
1月前
|
编译器 C语言 C++
C++入门6——模板(泛型编程、函数模板、类模板)
C++入门6——模板(泛型编程、函数模板、类模板)
41 0
C++入门6——模板(泛型编程、函数模板、类模板)
|
1月前
|
存储 安全 编译器
【C++打怪之路Lv1】-- 入门二级
【C++打怪之路Lv1】-- 入门二级
23 0
|
1月前
|
自然语言处理 编译器 C语言
【C++打怪之路Lv1】-- C++开篇(入门)
【C++打怪之路Lv1】-- C++开篇(入门)
24 0