跨平台C、C++代码注意的事项及如何编写跨平台的C/C++代码

    在我们的开发中,跨平台的需求越来越强烈,如何保持C/C++代码能在多个平台上编译,是一个比较值得研究的问题。关于跨平台的文章网上很多,跨平台的库网上也很多。那么我从自己的跨平台开发经验谈一谈自己的心得,希望对大家能够起到一定的作用。主要涉及到Windows和linux两个操作系统。

1、  关于路径和头文件路径分隔符的问题

在Windows中,正斜杠和反斜杠都可以,但是在Linux中,只能是/。

在Windows中,路径大小写无所谓,在Linux中严格区分大小写。

2、  char的问题

如果考虑跨平台,需要明确指定是signed或者unsigned,因为不同平台直接声明char,会导致signed或者unsigned的不确定性。

3、  关于宽字符的问题。

在Windows中,wchar_t占两个字节,Linux中占四个字节,但是在Linux可以指定两个字节,这样也会造成一个问题,就是某些第三方库中wchar_t可能只指定四个字节的,这样就会导致不兼容。

4、  Linux里面没有stricmp函数,在Linux下面是strcasecmp函数比较字符串。

5、  与平台相关的调用尽量用宏隔离开来,一般用不同的目录代表不同平台,BOOST、OGRE等是这样做,也可以再一个类或者文件中,这样会导致到处都是操作系统和编译器相关宏的定义。

6、  关于头文件包含

在Windows下某些C标准库的头文件不用显式包含,但是在linux下需要显式包含。所以在.c和.cpp文件中尽量包含这个文件中需要的头文件。

7、  注意机器大尾端和小尾端的区别

大小尾端对文件的读写会有很大影响,要编写跨平台c++程序,大小尾端是必须要考虑的问题。比如,你在大尾端机器上写了一个文件,然后在小尾端机器上读取,那么结果肯定是错误的,所以,我们设计文件格式时,都需要规定文件是大尾端存储还是小尾端存储,或者一个文件中规定某些部分是大尾端某些部分是小尾端。

8、  尽量只使用STL较早出现的函数或类

较早出现的东西相对来说比较稳定,STL的各个实现基本上都会有实现,这样跨平台的时候可以兼容多个平台。

9、  使用std::exception时需要注意,LINUX下是不支持抛出异常的,如果继承自标准库的异常类写自己的异常类的时候,在Linux下,子类的析构函数中就需要表明不抛出异常,所以析构函数后面加上throw()就可以了。

10、当继承模板类时。需要谨慎

在自己的代码中,需要继承模板类时,如果需要访问基类模板类的成员函数或者成员变量,前面加上this->。另外,构造函数需要用到基类进行构造时。基类的类型需要需要用该类的类型参数初始化,否则在linux下会提示找不到基类的这个名字。

11、尽量使用标准C和C++的函数以及STL,使用C语言中定义的类型。

12、头文件重复包含的问题

         尽量用保卫宏去实现防止头文件的重复包含,很多代码在Windows下直接用#pragma once,这不能保证跨平台需要。

13、关于结构体对齐的问题。

         CPU为了简化内存和CPU之间的处理以及加快CPU从内存中取数据的速度,往往都会做一定的对齐,即结构体的各个成员并不是紧凑存储的,往往在成员中间填充一些字节。所以,我们一般不推荐用结构体直接读取和写入数据,这样在不同系统或者计算机之间进行移植时,会出现错误的结果。

14、注意BOM的陷阱(字节顺序标记)

         如果你在Windows用记事本创建一个源文件,那么Windows会在文件最前面加上一个BOM标记,即所谓的字节顺序标记,这样的源码在Windows下没问题,但是在Linux下就编译不过,所以需要用其他的文本编辑器或者直接在VS里面创建源文件。Linux下gcc/g++不认带BOM标记的源文件。

15、注意调用函数时的形参类型和函数声明中参数列表的类型不匹配。这里特指有无const或者是否是引用参数。在Windows下的cl编译器没问题,linux下GCC/G++会报错。

16、注意两个尖括号不要连着写。例如std::vector<std::vector<int>> vec;在Windows下这么写完全没问题,那么在linux下就是编译不过,所以linux下可以在连续两个尖括号符号之间留一个空格,即std::vector<std::vector<int>  > vec;


 

其实,这些只是冰山一角,在跨平台C/C++开发上还需要做更多的探索。


怎样才能实现一套C/C++代码跨平台编译呢?应该注意哪些问题,下面对其进行总结。

         平台包括: windows7(32bit and 64bit), windows 8.1(32bit and 64bit, desktop, app store, metro ),windows phone, Mac(32bit and 64bit), iOS(32bit and 64bit, x86, x64, armv6,armv7-a, arm64), Linux(32bit and 64bit, x86, x64, mips, armv8-a), Android(32bitand 64bit, x86, x64, armv6, armv7-a, armv8-a).

         遇到的问题包括:

         (1).数据类型在不同平台有可能长度不一致;

         (2).重定义问题,在有些平台某个功能有多种语言实现,如C++,SIMD,汇编等;

         (3).在有些平台,库的前后位置放置不正确,如Linux, Mac链接时与库位置有关;

         (4).对于intel SIMD指令,在Linux/Mac和windows下,有些包含的头文件名字不一致,如在windows下用"intrin.h",在linux下用"x86intrin.h",而在mac下用"nmmintrin.h";

         (5). 在特定系统中有些与性能相关的实现需要关闭,如SIMD在中标麒麟或湖南麒麟Linux下是不支持的;

         (6). SIMD个别用法不一致不能使用统一方法导致编译出错,如__m128i在linux下不能直接提取子元素,而在windows下是可以的;

         (7). 在有些平台只有函数声明没有实现,有时会报编译错误;

         (8). 在用命令行编译和链接时,要保证编译和链接的配置参数保持完全一致;

         (9). 有些平台缺少必要的软件或插件导致编译错误;

         (10). 对于SIMD,有些机子配置偏低,支持SIMD指令有限;

         (11). 在移动平台,对armv6, armv7-a, armv8-a,它们支持的参数是不一致的,要区别对待,如-msoft-float参数,在armv6和armv7-a下是支持的,在armv8-a下是不支持的;

         (12).在有些平台,自动获取CPU架构及位数有误。

         下面是从网上汇总的一些关于跨平台开发时的一些注意事项:

         以下内容参考(http://loopjump.com/ten_rules_for_cross_platform_cpp/http://www.cppblog.com/johndragon/archive/2007/04/18/22204.html?opt=admin):

         (1).不要先开发后移植:当增加了一个功能或者修复了某个bug,开始就需要考虑所有的目标平台,并使得代码能够在所有的平台上正常工作。

         (2).将GUI代码作为不可复用代码

         (3).使用标准C/C++类型,不要使用特定于平台的类型。

         (4).只使用内置的 #ifdef 编译标志,不要自己发明轮子。

         (5).开发一个简单的可重用的跨平台的基础库,来隐藏每个平台的代码。

         (6).在所有的API中都使用Unicode(特别是UTF-8)。现在,Unicode在各个平台所有应用上都是100%支持的,UTF-8的一个好的性质是它向后兼容ASCII码。

         (7).不要使用第三方应用程序框架或者运行时环境来使你的代码跨平台。

         (8).程序中不要硬性编码与平台相关的任何常量,比如行分隔符、文件分隔符、路径分隔符等。

         (9).不同的操作系统,不同的机器,系统支持的颜色和屏幕的大小和分辨率都不同,要注意。

         (10).注意内存对齐。

         (11).注意文件名的大小写。

         (12).保证每个代码文件(.cpp, .h)的结尾都有单独的没有任何内容的一行,这在CC/GCC/G++编译器下能减少很多警告。

         (13).#include 包含头文件的时候一定要注意文件名的大小写。

         (14).头文件的路径分隔推荐使用”/”,而不是windows下常用的”\”,前者基本可以在所有系统上使用,后者似乎是windows独家支持的。

         (15).尽量使用标准C++的原子数据类型,避免使用被重新定义过的类型。或者自己重新重定义一套。

         (16).避免使用与编译器相关的一些特性。尽量所有代码都按照c++标准来编写。

         (17).尽量把操作系统相关的东西都封装成统一的调用接口,这样在移植代码的时候,可以做到重新编译即可运行。

         (18).尽量不要使用内嵌汇编。

         (19).在编译时尽量打开所有的警告选项,这样编译器可以尽可能多的发现平台相关的语句,并给出警告

         以下内容摘自《C++跨平台开发技术指南》 :

         (1).把所有的平台都放在同样重要的位置:必须在产品开发和发布的每一个阶段,都要在所有支持的平台上完全达到功能和质量的要求。

         (2).使用公共的代码:能被不同平台共享的代码越多,跨平台的项目就越容易成功。所有平台上公用的功能应该被标识出来避免它们在平台相关的代码里重复出现。并且它们的编译、测试和部署应该贯穿在整个产品生命期中。如果代码不能公用的话,应该把它隐藏到一个统一的API抽象之中去。这些封装平台相关功能的API对

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值