C与C++如何互相调用

news2025/1/23 17:40:49
img
个人主页:董哥聊技术
我是董哥,嵌入式领域新星创作者
创作理念:专注分享高质量嵌入式文章,让大家读有所得!
img

文章目录

    • 1、为什么会有差异?
    • 2、extern "C"
    • 3、C++调用C
      • 正确方式
    • 4、C调用C++
    • 5、总结

在项目开发过程中,我们底层代码经常用C来实现,而上层应用大都会用C++实现,这样我们就涉及到了CC++相互调用的情况了。那么,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

image-20221219154545328

 

我们分别使用gccg++单独编译文件,编译出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 @ 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不同编译方式之后的差别。

image-20221219160137798

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

 

正确方式

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

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

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

再次进行编译,即可!

image-20221219161410964

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

# 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

image-20221219162526678

 

我们分别使用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不同编译方式之后的差别。

image-20221219162704004

 

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

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

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

image-20221219163014548

 

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

image-20221219163536166

这个时候,会出现报错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_Learning/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
嵌入式艺术

 

5、总结

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

img

点赞+关注,永远不迷路

img

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/105293.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[第十二届蓝桥杯/java/算法]C——卡片

🧑‍🎓个人介绍:大二软件生,现学JAVA、Linux、MySQL、算法 💻博客主页:渡过晚枫渡过晚枫 👓系列专栏:[编程神域 C语言],[java/初学者],[蓝桥杯] &#x1f4d6…

中外法律文献查找下载常用数据库大盘点

中外法律文献查找下载常用数据库有: 一、Westlaw(法律全文数据库) 是法律出版集团Thomson Legal and Regulator’s于1975年开发的,为国际法律专业人员提供的互联网的搜索工具。 Westlaw International其丰富的资源来自法律、法规…

图(Graph)详解 - 数据结构

文章目录:图的基本概念图的存储结构邻接矩阵邻接矩阵的实现邻接表邻接表实现图的遍历图的广度优先搜索(BFS)图的深度优先搜索(DFS)最小生成树Kruskal算法Prim算法最短路径单源最短路径 - Dijkstra算法单源最短路径 - B…

Linux学习-91-Discuz论坛安装

17.22 Discuz论坛安装 通过 Discuz! 搭建社区论坛、知识付费网站、视频直播点播站、企业网站、同城社区、小程序、APP、图片素材站,游戏交流站,电商购物站、小说阅读、博客、拼车系统、房产信息、求职招聘、婚恋交友等等绝大多数类型的网站。Discuz!自2…

《教养的迷思》

在读《穷查理宝典》时,查理芒格在有一讲,专门谈及《教养的迷思》一书,说到作者朱迪斯哈里斯。查理芒格认为哈里斯在探求真理的道路上走得很顺利,取得成功的因素之一就是她热衷于摧毁自己的观念。 朱迪斯在书的开端首先严肃地纠正了…

【案例教程】无人机生态环境监测、图像处理与GIS数据分析综合实践

【查看原文】无人机生态环境监测、图像处理与GIS数据分析综合实践技术应用 构建“天空地”一体化监测体系是新形势下生态、环境、水文、农业、林业、气象等资源环境领域的重大需求,无人机生态环境监测在一体化监测体系中扮演着极其重要的角色。通过无人机航空遥感技…

Fabric系列 - 多通道技术(Muti-channel)

可在节点,通道和联盟级别上配置。 一个Fabric网络中能够运行多个账本,每个通道间的逻辑相互隔离不受影响,如下图所示,每种颜色的线条代表一个逻辑上的通道,每个Peer节点可以加入不同的通道,每个通道都拥有…

AI编译器XLA调研

文章目录一、XLA简介二、XLA在TensorFlow中的应用2.1 XLA是什么?(tensorflow\compiler\xla)2.2 TensorFlow怎样转化为XLA (tensorflow\compiler\tf2xla)2.3 JIT(just in time) 即时编译 (tensorflow\compil…

【大数据技术Hadoop+Spark】Flume、Kafka的简介及安装(图文解释 超详细)

Flume简介 Flume是Cloudera提供的一个高可用、高可靠、分布式的海量日志采集、聚合和传输的系统,Flume支持在日志系统中定制各类数据发送方,用于收集数据;同时,Flume提供对数据进行简单处理,并写到各种数据接受方&…

NLP学习笔记(四) Seq2Seq基本介绍

大家好,我是半虹,这篇文章来讲序列到序列模型 (Sequence To Sequence, Seq2Seq) 本文写作思路如下: 从循环神经网络的应用场景引入,介绍循环神经网络作为编码器和解码器使用,最后是序列到序列模型 在之前的文章中&am…

微信消息收发与微信内部emoji表情转义

微信消息收发与微信内部emoji表情转义 目录 微信内部emoji表情转义与消息收发 一、概述 二、常用标准emoji表情字符、微信内部转义符、unicode对照表 1、比如 2、微信聊天窗口emoji表情字符 2.1、PC端表情选择,01~03排: 2.2、PC端表情选择&#…

华为IMC培训——通信基础

目录 一、华为设备图标 二、数据的传递 三、专业术语 四、网络设备及相关知识 五、OSI七层模型 六、TCP和UDP数据报格式 七、TCP的三次握手 八、 TCP窗口滑动机制 一、华为设备图标 AP:相当于家用路由器一般配和AC使用。 AC和AP的区别_wangzhibo_csdn的博客…

创意被盗用,这3个加水印方法,让照片刻上我们专属印记

一般我们为了保护自己的图片不被别人盗用,都会选择在图片上刻上专属印记。那么便是加水印方法,它包含两种:文字水印和图片水印。想知道怎么给图片添加水印吗?其实有很多种法子可以做到,下面就由我来分享这3个简单好用的…

代码随想录刷题记录 day48 两个字符串的删除操作+编辑距离

代码随想录刷题记录 day48 两个字符串的删除操作编辑距离 583. 两个字符串的删除操作 思想 两个元素都能删除了,还是考虑第i-1个字符和第j-1个字符是不是相同的,不相同的话考虑三种情况,删除i-1;删除j-1,同时删除 1…

css实现鼠标禁用(鼠标滑过显示红色禁止符号)

css实现鼠标禁用(鼠标滑过显示红色禁止符号)创作背景css鼠标禁用创作背景 从本文开始,将会用三篇文章来一步一步实现vueantdts实战后台管理系统中table表格的不可控操作。中间会补充两篇css知识文章,方便后续功能的实现。实现表格…

非零基础自学Golang 第14章 反射 14.2 基本用法 14.2.2 获取类型的值 14.2.3 使用反射调用函数

非零基础自学Golang 文章目录非零基础自学Golang第14章 反射14.2 基本用法14.2.2 获取类型的值14.2.3 使用反射调用函数第14章 反射 14.2 基本用法 14.2.2 获取类型的值 Go语言使用reflect.TypeOf来获取类型信息,使用reflect.ValueOf来获取变量值的信息。 refle…

云原生|kubernetes|CKA真题解析-------(6-10题)

第六题: service配置 解析: 考察两个知识点: deployment控制器内的port命名 暴露一个pod内的端口到新建的服务内的 这里有一个需要注意的地方,没有告诉你deployment控制器在哪个namespace。假设这个front-end这个pod是在A这个…

前端CSS Flex布局8大重难点知识,收藏起来吧

2009年,W3C提出了一种新的方案—-Flex布局,可以简便、完整、响应式地实现各种页面布局。目前,它已经得到了所有浏览器的支持,这意味着,现在就能很安全地使用这项功能。 Flex布局将成为未来布局的首选方案。这也是学习前…

Spring之底层架构核心概念-BeanDefinition

目录1.什么是BeanDefinition?2.如何生成BeanDefinition?2.1. Component2.1. bean标签2.3. Bean注解2.4. AbstractBeanDefinition2.5. 利用BeanDefinition 读取器-解析类2.6. XmlBeanDefinitionReader - 解析 xml文件2.7. ClassPathBeanDefinitionScanner 扫描生成 …

2022年度回顾 | 技术篇:突破公链不可能三角的努力

2022年接近尾声,驻足回看行业这一年的跌宕起伏,无论是技术的突破,应用的创新,还是生态的兴衰,皆成为了行业发展的历史注脚。如往年一样,万向区块链于年末推出重磅年度回顾系列文章:《公链技术篇…