跨平台代码开发技巧

4 篇文章 0 订阅
4 篇文章 0 订阅

很多时候,我们需要自己的代码能够跑在多个平台上,例如 windows , Linux , Unix等,这对没有什么开发经验的程序员来说,这简直是个地狱,因此往往会先挑容易的平台进行开发,例如windows, 然后想办法将代码移植到Linux, 真到了移植的时候,往往发现这简直比从头开发还困难,移着移着心烦躁,由它去吧,只要windows平台跑的没问题,其他平台能编译过去就行,至于能稳定运行多少时间听天由命了.

我刚刚将自己的服务器程序,不到10万行的代码,从windows平台移植到Linux( ubuntu + centos),从开始移植到调试完成,一共就用了一个星期,非常顺利,这里写一点自己的心得.

非常重要的一点是, c/c++标准越老,那么可移植性越好,例如c89, 如果你的代码能用c89实现,那么就没必要用c++,更没必要c++11, c++17更是要绝对避免,因为你用c89编写的东西,就算是乞丐版的嵌入操作系统都能编译,而如果采用c++17标准, 很多长期稳定版的Linux都还需要升级编译器来支持,在各种函数上,如果可以使用标准库例如stdio.h等c/c++标准库的,就坚决不要使用原生api, 例如cout<< 这样的尽量避免,而应该使用printf来代替,如果函数标注了POSIX兼容,那这个函数基本是可以跨平台的,你可以大胆使用,即使Linux里没有,一般也很容易找到替代函数进行转换。

首先, 程序的内部数据必须使用UTF8为主编码, 千万不要使用windows unicode UTF16, 如果你在程序里大量使用wchar_t CString 这样的MFC库里的数据数据类型,那要跨平台基本就完蛋了,必须使用UTF8为内部编码格式,只有当必须使用windows本地API接口函数的时候,才使用MultiByteToWideChar进行字符串转换, 例如 扫描目录列表, findnext等函数都是UTF16的unicode编码, 获得的参数必须随时使用WideCharToMultiByte转换成UTF8编码保存,不要怕麻烦,不要使用VC专用的宏处理,否则到时候跨平台是无法移植的, 所有数据如果必须要用到模板保存,建议使用std系列,例如std::vector, std::string, 不建议使用boost等非标准库

对于整数的处理,特别是64位整数,建议统一使用__int64 这样的标准, 在Linux环境里, long long int ,建议使用一个

#ifndef _WIN32

#define _int64 long long int

#define PRI64T "%lld"

#else

#define PRI64T "%I64d"

#endif

而对于64位的输出,windows下是使用%I64d, 而Linux下使用 %lld (有些版本可能允许使用%ld), 这个暂时没有好办法,只能使用宏在format里进行处理, 不能写死

其次,对所有SOCKET 系列函数进行包装,一定要使用标准SOCKET,特别注意,select函数第一个参数,windows下没有意义,而Linux下是最大文件描述符+1,注意+1, 别去使用MFC扩展SOCKET或者Overlap/io等,否则移植简直是天塌了, 特别是sockaddr_in6,Linux和windows对结构的定义是不同的,这里没有捷径,建议使用#ifdef _WIN32  #else  #endif 进行处理, 自己编写一个头文件,对那些名称不同,但是参数和功能完全相同的函数进行重定义,例如

#ifndef _WIN32

#define sprintf_s snprintf

#define SOCKET int

......

#endif

因为sprintf_s在Linux是没有定义的,Linux里对应的函数是snprintf,有很多函数都可以这样处理,只是名称不同而已,还有memset等函数

Sleep函数,windows里的Sleep函数有时候挺好用,虽然Linux里有类似的函数,但是不建议你调用,而应该使用select(0...)来实现,这也是POSIX推荐的休眠方式,Linux里两个休眠函数都有点副作用。

windows环境下消息是非常有优势的,性能也非常好,因为windows很多东西本身就是消息驱动,但是Linux里,并没有象windows那样的消息系统,例如PostThreadMessage,这对调度内部线程非常方便,而pthread本身是没有消息驱动的,替代方法是使用Linux systemV消息系统, 采用一个线程一个消息池,或者全局一个消息池[但是不建议这么做,破坏代码的完整性],通过消息句柄进行处理,在Linux下对PostThreadMessage进行重新包装,这样原先windows下的消息驱动就不需要变更,可以完美移植过去。

Linux下编写网络程序,需要特别提醒的是,要注意处理PIPE_BROKEN信号,这是windows socket编程里没有,这个信号光在主线程里屏蔽还不够,需要每个线程屏蔽,否则一个不小心进程就结束了。

Windows下服务器程序需要写一堆的代码进行注册等操作,而在Linux,只需要调用daemon一个函数就可以,简单到不敢相信。

对于线程锁的处理,windows下CriticalSeciton效率是最高的,而Linux下,替代的是mutex,建议自己写一个包裹类进行处理,在多线程程序里,尽量避免使用锁操作,这对性能影响是非常大的. [这里特别提醒,如果你使用ubuntu Linux下高版本gcc,对你的代码进行静态编译,OK,编译连接没问题,但是运行的时候,如果你调用了pthread锁,会抛出异常并终止运行,恭喜你中招,而且你很难找到原因,就算搜索也找不到线索,我被这货坑了整整两天,动态连接运行没问题,静态就死悄悄,其实说到底,是这个gc库pthrread库里面符号冲突了,那么多thread,特别是c17引入了标准thread,当没有前缀强制指定引用的是那个入口,结果就连接到强符号上去了,而我们真正要连接的是弱符号,结果就出现了这种崩溃]

最后, 线程的处理, 强烈建议,非windows平台使用pthread库进行处理,而windows使用原生的thread函数(注意,不是AfxBeginThread, 而是使用_beginthreadex,因为这和pthread除了返回值不同,其他基本相同, 注意,虽然c++17引入了例如std::thread的线程,但是绝对不要在代码里使用,这种新的标准,没有10年8年的发展,很多编译器都是无法全部支持的,严重影响可移植性。

总结: 要进行跨平台移植,那么应该尽量使用低版本的c/c++标准,使用UTF8编码, 使用c/c++标准库,尽量不使用第三方库,如果你做到了上面几点,那么跨平台是非常容易的事情。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值