编写可移植C/C++程序的要点

2023-05-16

以前做过两年C/C++程序移植工作,从Win32平台移植到Linux平台。大约有上百万行C/C++代码,历时一年多。

在开发Win32版本时,已经强调了程序的可植性,无奈Win32团队里对Linux精通的人比较少,很多问题没有想到,直到后来移植工作开始时,才发现移植并非像想的那样简单。

后来,我发现大家对移植工程师都比较轻视,不管是从工资待遇还是管理层的态度来看都是这样。他们往往认为,你们不过是把别人实现好的东西移植过去罢了,你老老实实,按步就班去做就行了,根本不需要丝毫创意。

事实并非如此,特别是对于大项目,其中遇到的问题和困难可谓一言难尽。比如前面提到的那个项目,虽然过去好几年了,很多问题我仍然记忆犹新。

这里总结一些经验吧,这些经验,无一不是经过大量汗水换来的,有的引起的BUG甚至耗费数周时间才查出来。写出来,供类似的项目参考,不用再走这些弯路。

**1、分层设计,隔离平台相关的代码。**就像可测试性一样,可移植性也要从设计抓起。一般来说,最上层和最下层都不具有良好的可移植性。

最上层是GUI,大多数GUI都不是跨平台的,如Win32 SDK和MFC。最下层是操作系统API,大多部分操作系统API都是专用的。

如果这两层的代码散布在整个软件中,那么这个软件的可植性将非常的差,这是不言自明的。那么如何避免这种情况呢?当然是分层设计了:

最底层采用Adapter模式,把不同操作系统的API封装成一套统一的接口。至于封装成类还是封装成函数,要看你采用的C还是C++写的程序了。这看起来很简单,其实不尽然(看完整篇文章后你会明白的),它将耗去你大量的时间去编写代码,去测试它们。

采用现存的程序库,是明智的做法,有很多这样的库,比如,C库有glib(GNOME的基础类),C++库有ACE(ADAPTIVE Communication Environment)等等,在开发第一个平台时就采用这些库,可以大大减少移植的工作量。

最上层采用MVC模型,分离界面表现与内部逻辑代码。把大部分代码放到内部逻辑里面,界面仅仅是显示和接收输入,即使要换一套GUI,工作量也不大。

这同时也是提高可测试性的手段之一,当然还有其它一些附加好处。所以即使你采用QT或者GTK+等跨平台的GUI设计软件界面,分离界面表现与内部逻辑也是非常有用的。

若做到了以上两点,程序的可移植性基本上有保障了,其它的只是技术细节问题。

strongerHuang

,赞426

**2、事先熟悉各目标平台,合理抽象底层功能。**这一点是建立在分层设计之上的,大多数底层函数,像线程、同步机制和IPC机制等等,不同平台提供的函数,几乎是一一对应的,封装这些函数很简单,实现Adapter的工作几乎只是体力活。

然而,对于一些比较特殊的应用,如图形组件本身,就拿GTK+来说吧,基于X Window的功能和基于Win32的功能,两者差巨大,除了窗口、事件等基本概念外,几乎没有什么相同的,如果不事先了解各个平台的特性,在设计时就精心考虑的话,抽象出来的抽口在另外一个平台几乎无法实现。

3、尽量使用标准C/C++函数。大多数平台都会实现POSIX(Portable Operating System Interface)规定的函数,但这些函数较原生(Native) 函数来说,性能上的表现可能较次一些,用起来也不如原生函数方便。

但是,最好不要贪图这种便宜而使用原生函数函数,否则搬起的石头最终会轧到自己的脚。比如,文件操作就用fopen之类的函数,而不要用CreateFile之类的函数等。

**4、尽量不要使用C/C++新标准里出现的特性。**并不是所有的编译器都支持这些特性,像VC就不支持C99里面要求的可变参数的宏,VC对一些模板特性的支持也不全面。为了安全起见,这方面不要太激进了。

**5、尽量不要使用C/C++标准里没有明确规定的特性。**比如你有多个动态库,每个动态库都有全局对象,而且这些全局对象的构造还有依赖关系,那你迟早会遇到麻烦的,这些全局对象构造的先后顺序在标准里是没有规定的。

在一个平台上运行正确,在另外一个平台上可能莫明其妙的死机,最终还是要对程序作大量修改。

**6、尽量不要使用准标准函数。**有些函数大多数平台上都有,它们使用得太广泛了,以至于大家都把它们当成标准了,比如atoi(把字符串转换成整数)、strdup(克隆字符串)、alloca(在栈分配自动内存)等等。不怕一万,就怕万一,除非明白你在做什么,否则还是别碰它们为好。

**7、注意标准函数的细节。**也许你不相信,即使是标准函数,抛开内部实现不论,就其外在表现的差异也有时令人惊讶。这里略举几个例子:

(1) int accept(int s, struct sockaddr *addr, socklen_t *addrlen);addr/ addrlen本来是输出参数,如果是C++程序员,不管怎么样,你已经习惯于初始化所有的变量,不会有问题。如果是C程序员,就难说了,若没有初始化它们,程序可能莫名其妙的crash,而你做梦也怀疑不到它头它。这在Win32下没问题,在Linux下才会出现。

(2)int snprintf(char *str, size_t size, const char *format, …);第二个参数size,在Win32下不包括空字符在内,在Linux下包括空字符,这一个字符的差异,也可能让你耗上几个小时。

(3) int stat(const char *file_name, struct stat *buf);这个函数本身没有问题,问题出在结构stat上,st_ctime在Win32下代表创建(create)时间,在Linux下代表最后修改(change)时间。

(4)FILE *fopen(const char *path, const char *mode);在读取二进制文件,没有什么问题。在读取文本文件可要小心,Win32下自动预处理,读出来的内容与文件实际都长度不一样,在Linux则没有问题。

**8、小心数据标准数据类型。**不少人已经吃过int类型由16位转变成32位带来的苦头,这已经是陈年往事了,这里且不谈。

你可知道char在有的系统上是有符号的,在有的系统是无符号的吗?你可知道wchar_t在Win32下是16位的,在Linux 下是32位的吗?你可知道有符号的1bit的位域,取值是0和-1而不是0和1吗?这些貌合神离的东东,端的是神出鬼没,一不小心着了它的道。

**9、最好不要使用平台独有的特性。**比如Win32下DLL可以提供一个DllMain函数,在特定的时间,操作系统的Loader会自动调用这个函数。这类功能很好用,但最好不要用,目标平台可不能保证有这种功能。

**10、最好不要使用编译器特有的特性。**现代的编译器都做很人性化,考虑得很周到,一些功能用起非常方便。

像在VC里,你要实现线程局部存储,你都不调用TlsGetValue /Tls TlsSetValue之类的函数,在变量前加一个__declspec( thread )就行了,然而尽管在pthread里有类似的功能,却不能按这种方式实现,所以无法移植到Linux下。同样gcc也有很多扩展,是在VC或者其它编译器里所没有的。

**11、注意平台的特性。**比如:

在Win32下的DLL里面,除非明确指明为export的函数外,其它函数对外都是不可见的。而在Linux下,所有的非static的全局变量和函数,对外全部是可见的。这要特别小心,同名函数引起的问题,让你查上两天也不为过。

(1)目录分隔符,在Win32下用’//’,在Linux下用’/’。

(2)文本文件换行符,在Win32下用’/r/n’,在Linux下用’/n’,在MacOS下用’/r’。

(3)字节顺序(大端/小端),不同硬件平台的字节顺序可能不一样。

(4)字节对齐,在有的平台(如x86)上,字节不对齐,无非速度慢一点,而有的平台(如arm)上,它完全用错误的方式去读取数据,而且不会给你一点提示。若出问题,可能让你一点头绪都没有。

12、最好清楚不同平台的资源限制。想必你还记得DOS下同时打开的文件个数限制在几十个的情形吧,如今操作系统的功能已经强大多了,但是并非没有限制。比如Linux下的共享内存默认的最大值是4M。若你对目标平台常见的资源限制了然于胸,可能有很大的帮助,一些问题很容易定位。

可移植性的问题决不限于以上几种,一方面,即使以前遇到过的问题,部份已经忘记了。另外一方面,还有很多未知的问题,根本没有遇到过。这里算是抛砖引玉吧,请大家补充。

来源:

https://blog.csdn.net/absurd/article/details/622055

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

编写可移植C/C++程序的要点 的相关文章

  • Qt QFile文件操作详解

    文章目录 QFile文件操作QFile 43 QTextStreamQFile 43 QDataStream 文件操作是非常重要的 xff0c 是数据持久化的方法 通过文件操作 xff0c 我们可以把在软件中设置的数据保存起来 已剪辑自 h
  • Qt布局管理详解(5种布局控件)

    文章目录 QVBoxLayout垂直布局QHBoxLayout水平布局QGridLayout网格布局QFormLayout表单布局QStackedLayout分组布局 已剪辑自 http c biancheng net view vip 9
  • 基于优先级的时间片轮转调度算法(C语言实现)

    已剪辑自 http www demodashi com demo 15341 html 基于优先级的时间片轮转调度算法 1 PCB结构 xff08 Block xff09 由此定义如下结构体 xff1a span class token k
  • Qt自定义信号和槽函数

    文章目录 自定义信号函数自定义槽函数自定义信号和槽的完整实例 已剪辑自 http c biancheng net view vip 9662 html 实际开发中 xff0c 如果仅使用 Qt 提供的信号函数和槽函数 xff0c 会经常遇到
  • QT中信号和槽之间的参数传递和参数匹配

    已剪辑自 https blog csdn net lyc daniel article details 12047819 信号槽如何传递参数 xff08 或带参数的信号槽 xff09 利用Qt进行程序开发时 xff0c 有时需要信号槽来完成
  • QT使用信号与槽时编译错误“no matching function for call to connect“

    转转于 xff1a http t csdn cn K3aYh 初学QT xff0c 在尝试用connect手动关联一个按钮和QlineEdit的时候编译报错 xff0c 如下 xff1a 然后贴上主要代码块 xff1a span class
  • QT-QTableWidget中的cell和item的区别

    文章目录 QTableWidget中单击一个单元格响应不同的函数 xff1a cell和item的区别 xff1a 单击单元格响应自定义函数我的错误思路 xff1a 已剪辑自 https blog csdn net CCLasdfg art
  • QT开发网络调试助手项目总结

    之前整理了一些使用QT开发串口调试助手的项目 博客地址 xff1a 上位机总结 这次继续整理一些使用QT开发网络调试助手的项目 Qt开源作品41 网络调试助手增强版V2022 我的QT学习之路 xff0c 编写UDP 43 tcp网络调试助
  • QT开源项目总结-总有一款适合你

    Qt Open Source Project 开源项目推荐 xff1a 本人收集的有关Qt的GitHub Gitee开源项目 精品收藏 我的Qt作品 Github上的一些高分Qt开源项目 Qt编写项目作品大全 Qt 开源作品
  • Qt 打印调试信息-怎样获取QTableWidget的行数和列数-读取QTableWidget表格中的数据

    文章目录 Qt 打印调试信息怎样获取QTableWidget的行数和列数Qt怎么把QTableWidget表格中的数据读取出来 Qt 打印调试信息 打印当前目录代码如下 xff0c 别忘了头文件 include include lt QtD
  • VR游戏交互开发的一些体验

    VR游戏交互开发的一些体验 本文主要写Unity开发手游过程中VR交互输入控制的一些浅薄的经验交互方面 xff0c 头控和视线按钮依然较为主流 xff0c 可以获得传感器数据来获得输入除了实体按钮输入之外还可以探索其他交互方式 xff0c
  • 一篇文章快速搞懂Qt文件读写操作

    已剪辑自 https www cnblogs com jfzhu p 13546886 html 导读 xff1a Qt当中使用QFile类对文件进行读写操作 xff0c 对文本文件也可以与QTextStream一起使用 xff0c 这样读
  • 完整的PRD文档包含哪些内容?

    完整的PRD文档包含哪些内容 xff1f 千万 xff0c 千万 xff0c 千万别再套模板写需求文档了 xff0c 要想写好需求文档重要的不是包含哪些内容 xff0c 而是为什么包含这些内容 xff01 话不多说 xff0c 直接上干货
  • 分享一个开源的QT的串口示波器

    已剪辑自 https mp weixin qq com s XHELtvZ Wk2hNzsWD52D1w 直接来源 果果小师弟 逛github时看到这个QT的串口示波器 xff0c 完全开源 xff0c 支持串口 TCP 波形显示 通信协议
  • C 语言函数返回值,竟也有潜规则~

    已剪辑自 https mp weixin qq com s WNHx1zhna8iGaYIj6 3 fg 基本上 xff0c 没有人会将大段的C语言代码全部塞入 main 函数 更好的做法是按照复用率高 耦合性低的原则 xff0c 尽可能的
  • 模型在物理学发展中的作用

    已剪辑自 https mp weixin qq com s txS CQAIXPtY6kb2tHukUQ 模型是物理学认识由唯象理论过渡到动力学理论重要的环节 开普勒的行星运行模型 气体的分子运动模型 爱因斯坦的光子模型 卢瑟福 玻尔的原子
  • 第一性原理谈安全性和可靠性

    已剪辑自 https mp weixin qq com s jttd dhv9PmNu25Z zyd5Q 最近从各个行业对系统的安全性的关注度越来越高 xff0c 10月28日 xff0c 工信部公开征求的 道路机动车辆生产准入许可管理条例
  • 在浏览器地址栏输入一个URL后回车,背后会进行哪些技术步骤?

    转载于 xff1a 小林的图解网络系列 关键是要有个上帝视角 xff0c 先要有个网络模型的概念 xff0c 也就是TCP IP 四层网络模型 xff0c 然后针对每一层的协议进行深入 学习计算机网络一定要抓主一个点 xff0c 就是 输入
  • 在MacOS上实现两个网络调试助手的UDP通信测试

    文章目录 一 背景二 网络调试助手软件三 UDP通信过程 一 背景 因为有一个项目要中会使用本机中两个应用程序之间的UDP通信 因此本文记录一下怎么在MacOS上实现两个网络调试助手的UDP通信测试 二 网络调试助手软件 我使用的网络调试助
  • QT和网络调试助手之间的UDP通信

    文章目录 一 背景二 实现过程简述UDP协议工作原理及编程模型UDP 接收端UDP 发送端运行UDP接收端和发送端运行UDP发送端发送数据给网络调试助手 一 背景 之前一篇博客实现了两个网络调试助手之间的UDP通信 文章链接 xff1a 在

随机推荐

  • 一个开源且完全自主开发的国产网络协议栈

    已剪辑自 https mp weixin qq com s 1LE7mGc9mRuajRgNsyirQ onps是一个开源且完全自主开发的国产网络协议栈 xff0c 适用于资源受限的单片机系统 xff0c 提供完整地ethernet ppp
  • PyQt的使用

    使用conda切换到python3 如果不会使用conda xff0c 那么安装anaconda后打开navigator xff0c 再environments中选择创建好的python3环境 xff0c 右键打开terminal即可 安装
  • 前后台系统及嵌入式前后台模式实时性优化

    一 前后台系统 前后台系统 xff0c 即计算机前后台系统 xff0c 早期的嵌入式系统中没有操作系统的概念 xff0c 程序员编写嵌入式程序通常直接面对裸机及裸设备 xff0c 在这种情况下 xff0c 通常把嵌入式程序分成两部分 xff
  • 又一嵌入式开源仿真器

    已剪辑自 https mp weixin qq com s X0I3EotJ8TRqLK8vb8iQvA 同QEMU类似 xff0c Renode也是嵌入式相关的一个模拟器 Renode 针对物联网应用 xff0c QEMU 针对 PC 模
  • SkyEye天目全数字实时仿真软件功能介绍

    文章目录 SkyEye的概念和应用 SkyEye的优势 SkyEye可与第三方语言或者模型集成 基于可视化图形的硬件建模 容器化的仿真平台 FPGA协同仿真 SkyEye的应用案例 SkyEye大规模航电系统仿真案例 SkyEye 飞行器显
  • SkyEye——如何实现1553B总线仿真?

    已剪辑自 https www digiproto com news 204 html 1553B最初是美国军方专为飞机上设备制定的一种信息传输总线标准 xff0c 具有双向传输的特性 xff0c 实时性和可靠性高 xff0c 现已广泛应用于
  • 细数SkyEye异构仿真的5大特色

    已剪辑自 https www digiproto com news 65 html 航天飞行器使用仿真器的重要性 航天飞行器如卫星 载人飞船等需要在空中运行很长的时间 xff0c 如果出现问题回收再调试可能要历时几个月 xff0c 而且不得
  • SkyEye:航空发动机控制系统仿真

    已剪辑自 https www digiproto com news 212 html 航空发动机 xff08 aero engine xff09 是一种高度复杂和精密的热力机械 xff0c 作为飞机的心脏 xff0c 不仅是飞机飞行的动力
  • 基于功能安全的车载计算平台开发:软件层面

    已剪辑自 https mp weixin qq com s SIBvH8u vCk6W28KrPBmA 车载智能计算平台作为智能汽车的安全关键系统 xff0c 软件层面的安全性至关重要 由于车载智能计算平台功能丰富 xff0c 应用场景复杂
  • 软件和硬件中的调用

    文章目录 1 概述 2 1 程序进程内的调用 xff1a 函数调用 2 2 程序进程间的调用 xff1a IPC 2 3 远程程序调用 xff1a RPC 2 4 远程调用REST 3 硬件 调用 3 1 综述 总线模型 3 2 片内的总线
  • 软件和硬件之间的数据交互接口

    已剪辑自 链接 编者按 软件和硬件 xff0c 既相互依存又需要某种程度上的相互独立 通过软件和硬件之间的接口把两者连接在一起 软硬件接口 xff0c 有很多含义 xff1a 比如指令集是CPU软件和硬件之间的接口 xff1b 比如一些硬件
  • 硬件定义软件?还是,软件定义硬件?

    文章目录 1 软件和硬件 1 1 软件和硬件的定义 1 2 硬件定义软件 和 软件定义硬件 的定义 1 3 CPU xff0c 软件和硬件解耦 1 4 CPU的软硬件定义 2 硬件定义软件 2 1 系统从软件逐步到硬件 2 2 硬件架构决定
  • Matlab下多径衰落信道的仿真

    衰落信道参数包括多径扩展和多普勒扩展 时不变的多径扩展相当于一个延时抽头滤波器 xff0c 而多普勒扩展要注意多普勒功率谱密度 xff0c 通常使用Jakes功率谱 高斯 均匀功率谱 多径衰落信道由单径信道叠加而成 xff0c 而单径信道中
  • 硬件接口和软件接口

    文章目录 硬件接口IDESCSISATA光纤通道游戏设备RAID卡USBMD设备MP3视频音频 软件接口Java里的接口面向对象的接口 聊聊软件接口1 什么是接口2 诞生3 早期 xff08 1950 1970 xff09 4 快速发展 x
  • 有关C语言,定时器,周期任务的一些文章汇总

    测试C语言中打印一句 hello world需要耗费多少时间 C C 43 43 开源库 适合嵌入式的定时器调度器 C语言实现的多线程定时器 C语言操作时间函数 xff0c 实现定时执行某个任务小程序 C语言实现任务调度与定时器 Linux
  • SCADE简单了解

    随着新能源三电 智能驾驶等新技术的应用 xff0c 汽车中衍生出很多的安全零部件 xff0c 如BMS VCU MCU ADAS等 xff0c 相应的软件在汽车中的比重越来越大 xff0c 随之而来的安全性 可靠性要求也越来越高 ANSYS
  • 冯诺依曼体系结构与操作系统

    文章目录 详解冯诺依曼体系结构与操作系统前言1 简要背景介绍2 五大部件介绍3 细节解释4 举例理解冯诺依曼机中数据走向 二 全面认识操作系统1 操作系统的概念2 计算机系统 比对 银行系统3 深入认识 管理 xff1a 5 操作系统存在的
  • ADAS系统安全架构设计及安全等级的分解

    已剪辑自 https mp weixin qq com s PaFQDUR iOnEeueYQ82m w 笔者从事功能安全领域工作八年有余 xff0c 结合个人经验分享一下对系统安全架构设计的理解 xff0c 希望能够解决部分同行对于安全架
  • 汽车电子电气架构演进驱动主机厂多重变化

    已剪辑自 https mp weixin qq com s P56MaFODVc eZ4JEOVJvfA 汽车电子电气架构 xff08 EEA xff0c Electrical Electronic Architecture xff09 把
  • 编写可移植C/C++程序的要点

    以前做过两年C C 43 43 程序移植工作 xff0c 从Win32平台移植到Linux平台 大约有上百万行C C 43 43 代码 xff0c 历时一年多 在开发Win32版本时 xff0c 已经强调了程序的可植性 xff0c 无奈Wi