C++:C与C++混合编程

news2024/10/6 12:21:38

混合编程

  • 为什么需要混合编程
    (1)C有很多优秀成熟项目和库,丢了可惜,重写没必要,C++程序里要调用
    (2)庞大项目划分后一部分适合用C,一部分适合用C++
    (3)其他情况,如项目组一部分人习惯用C,一部分习惯用C++

  • 为什么不同语言可以混合编程
    (1)程序编译过程:源文件->目标(库)文件->可执行程序->镜像文件
    (2)任何编程语言执行时都必须是可执行程序,所以都必须先被编译成目标文件
    (3)混合编程的“混合”操作发生在链接这一步

  • C++和C混合编程的困难所在
    (1)C++和C都是编译型语言,互相混合相对容易
    (2)难点:C++支持函数名重载,而C不支持,因此编译器生成目标文件时,函数名在目标文件中的临时内部名称规则不同。导致链接时符号对不上
    (3)解决方案:使用extern “C”{}; 让C++在对接的局部向C妥协兼容
    通用解决方案:在C的头文件中加extern "C"声明,在C++中直接包含头文件调用即可

  • 使用objdump工具来研究函数编译后的符号
    (1)写个典型的C语言库mylib.c和mylib.h,提供add和sub等几个函数
    (2)使用gcc -c -o编译得到库文件,再objdump -d反汇编得到.i文件
    (3)对比加不加extern "C"这2种情况下得到的.i文件的符号差异
    实验第1步:证明了C语言中名称为add的函数,编译后符号表中就叫add

gCC -c clib.c -o clib.o
objdump -d clib.o > clib.i
gCC -c clib.c -o clib2.o
objdump -d clib2.o > clib.i

在这里插入图片描述

实验第2步:证明了C++语言中名称为add的函数,编译后符号表中叫_Z3addii
分析:同样的源码,编译后生成的二进制代码其实是一样的,所以功能其实也是一样的
所以本质上是可以混合编程的,但是生成的中间符号名称不同,所以链接器难受
实验第3步:证明了在C++的头文件中,只要把C++的函数的声明放在extern “C”{}的大括号范围之内,就可以让g++在编译这个函数时生成中间符号名时按照C的规则而不是按照C++的规则,所以这样的函数就可以和C的库进行共同链接。


extern "C" {
void fun();
}

#if __cplusplus
extern "C" {
#endif

#if __cplusplus
}
#endif
  • #if __cplusplus: 这是一个预处理器指令,用于检查当前代码是否在 C++ 环境中编译。__cplusplus 是一个预定义的宏,它在编译 C++ 代码时被定义为一个年份值,比如 199711L 或更高。因此,#if __cplusplus 的作用是在编译时判断是否为 C++ 环境。

  • extern “C”: 这是 C++ 提供的一种语法,用于告诉编译器按照 C 的方式对待包裹在其中的代码。在 C++ 中,函数名会被编译器进行名称修饰(name mangling),以支持函数重载和命名空间等特性。而 C 中没有这些特性,函数名不会进行修饰。因此,当 C++ 调用 C 的函数时,需要使用 extern “C” 来告诉编译器按照 C 的方式来处理函数名,以便在链接时能够正确找到对应的函数。

  • #endif: 这是预处理器指令,表示条件编译的结束。与 #if 配对使用,用于结束条件编译的代码块

预编译

g++ -E main.cpp -o main.i

生产静态库

ar -r libclib.a clib.o
g++ main.cpp -lclib -L.

C调用C++库的方法

代码实战:C调用C++库中的函数

构建C++库

gcc cppadd.cpp -c -o cppadd.o
ar -r libcppadd.a cppadd.o

反编译查看信息

 objdump -d libcppadd.a > libcppadd.i

在这里插入图片描述
test.c

在这里插入代码片
extern int _Z3addii(int a,int b);

int main(void)
{
    _Z3addii(1,2);
    return 0;
}
gcc test.c -lcppadd -L.

解决方案:添加一层封装层

g++ cppaddwrapper.cpp -c -o cppaddwrapper.o -lcppadd -L.
ar -r libcppaddwrapper.a cppaddwrapper.o
objdump -d libcppaddwrapper.a > cppaddwrapper.i

在这里插入图片描述

 gcc test.c -lcppaddwrapper -lcppadd -L. 

因为一开始的add是这样编写的

int add(int a, int b) {
  cout << "a + b = " << a + b << endl;
  return 0;
}

#include "cppadd.hpp"的引入放在cppaddwrapper.cpp

还是会出现报错。提示有东西没有引入

/usr/bin/ld: ./libcppadd.a(cppadd.o): warning: relocation against _ZSt4cout' in read-only section .text’
/usr/bin/ld: ./libcppadd.a(cppadd.o): in function add(int, int)': cppadd.cpp:(.text+0x1f): undefined reference to std::cout’
/usr/bin/ld: cppadd.cpp:(.text+0x27): undefined reference to std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)' /usr/bin/ld: cppadd.cpp:(.text+0x3c): undefined reference to std::ostream::operator<<(int)’
/usr/bin/ld: cppadd.cpp:(.text+0x43): undefined reference to std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)' /usr/bin/ld: cppadd.cpp:(.text+0x4e): undefined reference to std::ostream::operator<<(std::ostream& (*)(std::ostream&))’
/usr/bin/ld: ./libcppadd.a(cppadd.o): in function __static_initialization_and_destruction_0(int, int)': cppadd.cpp:(.text+0x85): undefined reference to std::ios_base::Init::Init()’
/usr/bin/ld: cppadd.cpp:(.text+0xa0): undefined reference to `std::ios_base::Init::~Init()’
/usr/bin/ld: warning: creating DT_TEXTREL in a PIE
collect2: error: ld returned 1 exit status

#include "cppadd.hpp"的引入放在cppaddwrapper.cpp
还是会出现报错。提示有东西没有引入

/usr/bin/ld: ./libcppaddwrapper.a(cppaddwrapper.o): in function addwrapper': cppaddwrapper.cpp:(.text+0x1d): undefined reference to add’
collect2: error: ld returned 1 exit status

总结

理解混合编程的存在性,知道解决方法

学习记录,侵权联系删除。
来源:朱老师物联网大课堂

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

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

相关文章

FormLayout布局和FormItem对比

FormLayout布局和FormItem对比 FormLayout布局 package mainimport ("fyne.io/fyne/v2""fyne.io/fyne/v2/app""fyne.io/fyne/v2/container""fyne.io/fyne/v2/layout""fyne.io/fyne/v2/widget" )func main() {myApp : app.…

代码随想录-Day45

198. 打家劫舍 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&#xff0c;系统会自动报警。 给定一个代表每个…

三维家:SaaS的IT规模化降本之道|OceanBase 《DB大咖说》(十一)

OceanBase《DB大咖说》第 11 期&#xff0c;我们邀请到了三维家的技术总监庄建超&#xff0c;来分享他对数据库技术的理解&#xff0c;以及典型 SaaS 场景在数据库如何实现规模化降本的经验与体会。 庄建超&#xff0c;身为三维家的技术总监&#xff0c;独挑大梁&#xff0c;负…

IDEA Debug 断点

今天在工作发现有些新入职的小伙伴们&#xff0c;在调试程序时不是很会正确使用IDEA所提供Breakpoints(断点)&#xff0c;这里就简单的介绍下比较常用的功能。 快捷键&#xff1a; 切换行断点&#xff1a;Ctrl F8 编辑断点属性&#xff1a;Ctrl Shift F8 断点的类型 行断点&am…

数据质量管理-可访问性管理

前情提要 根据GB/T 36344-2018《信息技术 数据质量评价指标》的标准文档&#xff0c;当前数据质量评价指标框架中包含6评价指标&#xff0c;在实际的数据治理过程中&#xff0c;存在一个关联性指标。7个指标中存在4个定性指标&#xff0c;3个定量指标&#xff1b; 定性指标&am…

文献阅读:逆行病毒示踪剂之间的神经嗜性和神经毒性的差异

文献介绍 文献题目&#xff1a; Differences in neurotropism and neurotoxicity among retrograde viral tracers 研究团队&#xff1a; 曹罡&#xff08;华中农业大学&#xff09;、戴金霞&#xff08;华中农业大学&#xff09; 发表时间&#xff1a; 2019-02-08 发表期刊&…

cefsharp(winform)默认菜单/自定义菜单/二级菜单定义方法

一、有关cefsharp(winform)菜单定义 接口:IContextMenuHandler 菜单:OnBeforeContextMenu 命令:OnContextMenuCommand void IContextMenuHandler.OnBeforeContextMenu(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IContextMenuParams parameters,…

智慧公厕系统改变了人们对服务区公厕的看法

在过去&#xff0c;服务区公厕常常给人留下脏乱差的印象&#xff0c;成为人们在长途旅行途中不愿停留的地方。然而&#xff0c;随着智慧科技的不断发展和应用&#xff0c;智慧公厕系统的出现改变了人们对服务区公厕的看法&#xff0c;为公共卫生设施的提升注入了新的活力。 一、…

常见反爬及应对

一&#xff0c;特殊混淆的还原 1.1 还原 AAEncode 与 JJEncode AAEncode是一种JavaScript代码混淆算法&#xff0c;利用它&#xff0c;可以将代码转换成 颜文字 表示的JavaScript代码。 去掉代码最后的 (‘‘)&#xff0c;这是函数的自调用&#xff0c;去除后就是函数的声明…

嵌入式存储介质之SD卡基础知识记录

嵌入式存储介质之SD卡 SD卡简介&#xff1a; SD卡&#xff08;Secure Digital Card&#xff0c;安全数字卡&#xff09;是一种广泛应用的可移除存储设备&#xff0c;主要用于存储各种数字信息&#xff0c;如照片、视频、音乐和文档等。SD卡由SD协会&#xff08;Secure Digita…

Golang 开发实战day15 - Input info

&#x1f3c6;个人专栏 &#x1f93a; leetcode &#x1f9d7; Leetcode Prime &#x1f3c7; Golang20天教程 &#x1f6b4;‍♂️ Java问题收集园地 &#x1f334; 成长感悟 欢迎大家观看&#xff0c;不执着于追求顶峰&#xff0c;只享受探索过程 Golang 开发实战day15 - 用户…

SSM学习3:注解开发定义bean、纯注解开发模式、注解开发依赖注入、注解开发管理第三方bean

注解开发定义bean 使用注解加载bena applicationContext.xml 配置组件扫描 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:context"http://www.springframework.o…

Linux文件管理:文件扩展属性 chattr lsattr 命令详解

目录 chattr命令常用参数属性选项完整的支持的属性选项 使用案例 lsattr命令常用参数使用案例 结合使用chattr和lsattr 在Linux系统中&#xff0c;文件属性决定了文件的可见性、可读性、可写性等特性。chattr和lsattr是两个用于管理文件系统属性的重要工具。 它们可以帮助用户保…

STM32智能家居掌上屏实战:从WiFi连接到MQTT通信,打造你的家庭物联网网关

摘要: 本文深入探讨一种基于STM32的智能家居掌上屏设计方案&#xff0c;详细阐述其硬件架构、软件设计以及通信协议等关键技术细节。该方案利用WiFi构建局域网&#xff0c;实现与各类传感器、执行器的便捷交互&#xff0c;并通过TFT彩屏提供直观的控制和数据展示&#xff0c;旨…

数组-二分查找

二分查找 leetcode704 /*** param {number[]} nums* param {number} target* return {number}*/ var search function(nums, target) {let left 0, right nums.length - 1;while (left < right) {const mid Math.floor((right - left) / 2) left;const num nums[mid]…

深入理解ThreadLocal原理

以下内容首发于我的个人网站&#xff0c;来这里看更舒适&#xff1a;https://riun.xyz/work/9898775 ThreadLocal是一种用于实现线程局部变量的机制&#xff0c;它允许每个线程有自己独立的变量&#xff0c;从而达到了线程数据隔离的目的。 基于JDK8 使用 通常在项目中是这样…

仅1月出刊:计算机科学类知网检索普刊

【欧亚科睿学术】 Journal of Computer Science and Electrical Engineering 《计算机科学与电气工程杂志》是一份同行评审期刊&#xff0c;发表计算机科学和电气工程几个领域的原创研究文章和综述文章。 它由UPUBSCIENCE出版社出版。它支持开放获取政策&#xff0c;即让所有…

后台运行大师:HarmonyOS 3.0中如何轻松设置APP常驻后台

有不少人想要让某些常用的APP直接挂在后台&#xff0c;减少应用程序自动关闭的情况。这种需求&#xff0c;其实就是希望APP能够“保持在后台运行”。 本篇文章用14张图片、7大步骤&#xff0c;讲解手机如何将某个APP保持在后台运行。图片直接使用的是华为手机HarmonyOS 3.0的手…

Verilog开源项目——百兆以太网交换机(五)TCAM单元设计

Verilog开源项目——百兆以太网交换机&#xff08;五&#xff09;TCAM单元设计 &#x1f508;声明&#xff1a;未经作者允许&#xff0c;禁止转载 &#x1f603;博主主页&#xff1a;王_嘻嘻的CSDN主页 &#x1f511;全新原创以太网交换机项目&#xff0c;Blog内容将聚焦整体架…

iptables防火墙详解、相关命令示例

目录 Linux包过滤防火墙 包过滤的工作层次 iptables的链结构 规则链 默认包括5中规则链&#xff08;对数据包控制的时机&#xff09; iptables的表结构 规则表 默认包括4个规则表 数据包过滤的匹配流程 规则表之间的顺序 规则链之间的顺序 规则链内的匹配顺序 匹配…