开发者

C和C++如何实现互相调用详解

开发者 https://www.devze.com 2023-01-10 11:17 出处:网络 作者: 卍一十二画卍
目录前言1、为什么会有差异?2、extern “C”3、C++调用C正确方式4、C调用C++补充:C/C++文件之间函数的引用总结前言
目录
  • 前言
  • 1、为什么会有差异?
  • 2、extern “C”
  • 3、C++调用C
    • 正确方式
  • 4、C调用C++
    • 补充:C/C++文件之间函数的引用
      • 总结

        前言

        在项目开发过程中,我们底层代码经常用C来实现,而上层应用大都会用C++实现,这样我们就涉及到了C和C++相互调用的情况了。那么,C/C++如何实现相互调用呢?

        1、为什么会有差异?

        • 编译方式不同C文件常采用gcc编译,而Cpp文件常采用g++来编译C++
        • 支持函数重载:由于这一特性,C++C中的同一个函数,经过编译后,生成的函数名称是不同的。

        这样就导致了CC++之间不能直接进行调用,要解决这一问题,就得靠extern "C"来辅助了。

        2、extern “C”

        • extern

        extern关键字我们并不陌生,它是编程语言中的一种属性,用来表示变量,函数等类型的作用范围。

        我们经常在.c源文件中定义变量或者实现函数,在.h头文件中使用extern关键字进行声明,方便其他文件调用。

        “C”

        编程语言种类繁多,不同语言有不同的编译规则,如果想要互相调用,必须告诉编译器以什么规则去编译文件,这样才能正常调用。

        其主要作用是:把“C”当作一个标志位,告诉编译器,下面代码以C的方式编译!

        了解其中原理后,我们来实操一下!

        3、C++调用C

        我们创建3个文件,分别为main.cppcal.ccal.h

        C和C++如何实现互相调用详解

        我们分别使用gccpythong++单独编译文件,编译出cal.omain.o两个中间文件,很简单,定义了一个embedded_art的函数。

        # dong @ Ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test on git:main x [15:57:32] 
        $ ls
        cal.c  cal.h  main.cpp
        
        # dong @ ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test on git:main x [15:57:43] 
        $ gcc -c cal.c 
        
        # dong @MbvbOPGMJu ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test on git:main x [15:57:49] 
        $ g++ -c main.cpp 
        
        # dong @ ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test on git:main x [15:57:55] 
        $ ls
        cal.c  cal.h  cal.o  main.cpp  main.o
        

        下面看一下编译之后的中间文件cal.omain.o的符号表,看看同一个函数embedded_art不同编译方式之后的差别。

        C和C++如何实现互相调用详解

        可以看到,g++编译之后,对函数名称进行了加工,按照自身的编译规则,最终生成了一个新的函数名,所以我们如果直接调用cal.c中的embedded_art肯定是不行的。

        正确方式

        使用extern "C"来使g++编译器用C的方式编译。

        main.cpp文件中,我们引入cal.h的位置,添加extern "C"

        extern "C" {
        #include "cal.h"
        }
        

        再次进行编译,即可!

        C和C++如何实现互相调用详解

        可以看到符号表中,该函数名称正常,然后我们将中间文件链接起来,执行,输出正确结果!

        # dong @ ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test on git:main x [16:18:36] 
        $ g++ main.o cal.o 
        
        # dong @ ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test on git:main x [16:19:54] 
        $ ls
        a.out  cal.c  cal.h  cal.o  main.cpp  main.o
        
        # dong @ ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test on git:main x [16:19:57] 
        $ ./a.out 
        main entry
        嵌入式艺术
        

        4、C调用C++

        我们创建3个文件,分别为main.ccal.cppcal.h

        C和C++如何实现互相调用详解

        我们分别使用gccg++单独编译文件,编译出cal.omain.o两个中间文件,很简单,同样定义了一个embedded_art的函数。

        # dong @ ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test/c_call_c++ on git:main x [16:24:45] 
        $ g++ -c cal.cpp   
        
        # dong @ ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test/c_call_c++ on git:main x [16:24:52] 
        $ gcc -c main.c    
        
        # dong @ ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test/c_call_c++ on git:main x [16:24:56] 
        $ ls
        cal.cpp  cal.h  cal.o  main.c  main.o
        

        下面看一下编译之后的中间文件cal.omain.o的符号表,看看同一个函数embedded_art不同编译方式之后的差别。

        C和C++如何实现互相调用详解

        同样,不同的编译器处理方式不同,函数名称依旧不同!同样,需要加入extern "C"来告诉编译器按C的方式编译。

        我们在cal.h的声明部分添加,然后重新编译!

        extern "C" {
        extern void embedded_art(void);
        }
        

        C和C++如何实现互相调用详解

        可以看到符号表中,该函数名称正常,然后我们将中间文件链接起来。

        C和C++如何实现互相调用详解

        这个时候,会出现报错extern "C",这是什么情况?

        main.c文件中,引入了c++的头文件cal.h,因为"C"C++编译的时候才能识别,C语言中并没有这个关键字。

        所以,我们需要在g++编译的时候去加入extern "C",而gcc编译的时候跳过,这个时候就要提到c++编译时候的特定宏__cplusplus了,相当于一个阀门了。

        我们修改cal.h文件

        #ifdef __cplusplus
        extern "C" {
        #endif
        
        extern void embedded_art(void);
        
        #ifdef __cplusplus
        }
        #endif
        

        这样就确保了,c++编译embedded_art函数的时候,采用C语法编译,而gcc编译的时候,不作处理。

        再次链接,执行!

        # dong @ ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test/c_call_c++ on git:main x [16:45:06] C:1
        $ gcc -no-pie cal.o main.o -o main
        
        # dong @ ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Lear开发者_开发入门ning/c_c++_call_test/c_call_c++ on git:main x [16:46:46] 
        $ ls
        cal.cpp  cal.h  cal.o  main  main.c  main.o
        
        # dong @ ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test/c_call_c++ on git:main x [16:49:01] 
        $ ./main
        main entry
        嵌入式艺术
        

        补充:C/C++文件之间函数的引用

        C通过加"中间层"来引用C++(不用修改原Cjs++文件)

        //C文件
         
        int MyMax(int, int);
         
        int main()
        {
        	int a = 10;
        	int b = 20;
         
        	printf("%d\n", MyMax(a,b));
         
        	return 0;
        }
        //C++文件
        int Max(int a, int b)
        {
        	return a > b ? a : b;
        }
        //中间层//C++文件
         
        int Max(int ,int);
         
        extern "C"
        {
        	int MyMax(int a, int b)
        	{
        		return Max(a, b);
        	}
        }

        关键点:本文件之间的函数调用,不牵扯到函数符号的生成。比如中间层那个文件:C++格式的声明,C的引用(return Max(a,b)),不会牵扯到什么链接失败,那是发生在编译期间的,不牵扯到符号之间的解析。

        总结

        C/C++之间的相互调用,归根到底就是:不同的语言有不同的编译规则,要想实现通用,就必须告诉编译器,按照目标语言的规则进行编译!

        到此javascript这篇关于C和C++如何实现互相调用的文章就介绍到这了,更多相关C和C++互相调用内容请搜索我们以前php的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

        0

        精彩评论

        暂无评论...
        验证码 换一张
        取 消