$c++$编写可移植CC++程序的要点

编写可移植CC++程序的要点

1.分层设计,隔离平台相干的代码。就像可测试性一样,可移植性也要从设计抓起。一般来说,最上层和最下层都不具有良好的可移植性。最上层是GUI,大多数GUI都不是跨平台的,如Win32SDK和MFC。最下层是操作系统API,大多部份操作系统API都是专用的。如果这两层的代码散布在全部软件中,那末这个软件的可植性将非常的差,这是不言自明的。那末如何避免这种情况呢?固然是分层设计了:最底层采取Adapter模式,把不同操作系统的API封装成一套统一的接口。至于封装成类还是封装成函数,要看你采取的C还是C++写的程序了。这看起来很简单,其实不尽然(看完整篇文章后你会明白的),它将耗去你大量的时间去编写代码,去测试它们。采取现存的程序库,是明智的做法,有很多这样的库,比如,C库有glib(GNOME的基础类),C++库有ACE(ADAPTIVECommunicationEnvironment)等等,在开发第一个平台时就采取这些库,可以大大减少移植的工作量。最上层采取MVC模型,分离界面表现与内部逻辑代码。把大部分代码放到内部逻辑里面,界面仅仅是显示和接收输入,即便要换一套GUI,工作量也不大。这同时也是提高可测试性的手段之一,固然还有其它一些附加好处。所以即便你采取QT或GTK+等跨平台的GUI设计软件界面,分离界面表现与内部逻辑也是非常有用的。若做到了以上两点,程序的可移植性基本上有保障了,其它的只是技术细节问题。

2.事前熟习各目标平台,公道抽象底层功能。这一点是建立在分层设计之上的,大多数底层函数,像线程、同步机制和IPC机制等等,不同平台提供的函数,几近是逐一对应的,封装这些函数很简单,实现Adapter的工作几近只是体力活。但是,对一些比较特殊的运用,如图形组件本身,就拿GTK+来说吧,基于XWindow的功能和基于Win32的功能,二者差巨大,除窗口、事件等基本概念外,几乎没有甚么相同的,如果不事前了解各个平台的特性,在设计时就精心斟酌的话,抽象出来的抽口在另外一个平台几近没法实现。

3.尽可能使用标准C/C++函数。大多数平台都会实现POSIX(PortableOperatingSystemInterface)规定的函数,但这些函数较原生(Native)函数来讲,性能上的表现可能较次一些,用起来也不如原生函数方便。但是,最好不要贪图这类便宜而使用原生函数函数,否则搬起的石头终究会轧到自己的脚。比如,文件操作就用fopen之类的函数,而不要用CreateFile之类的函数等。

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

5.尽可能不要使用C/C++标准里没有明确规定的特性。比如你有多个动态库,每一个动态库都有全局对象,而且这些全局对象的构造还有依赖关系,那你早晚会遇到麻烦的,这些全局对象构造的前后顺序在标准里是没有规定的。在一个平台上运行正确,在另外一个平台上可能莫明其妙的死机,终究还是要对程序作大量修改。

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

7.注意标准函数的细节。或许你不相信,即便是标准函数,抛开内部实现不论,就其外在表现的差异也有时使人惊讶。这里略举几个例子:intaccept(ints,structsockaddr*addr,socklen_t*addrlen);addr/addrlen本来是输出参数,如果是C++程序员,不管怎样,你已经习惯于初始化所有的变量,不会有问题。如果是C程序员,就难说了,若没有初始化它们,程序可能稀里糊涂的crash,而你做梦也怀疑不到它头它。这在Win32下没问题,在Linux下才会出现。intsnprintf(char*str,size_tsize,constchar*format,……);第二个参数size,在Win32下不包括空字符在内,在Linux下包括空字符,这一个字符的差异,也可能让你耗上几个小时。intstat(constchar*file_name,structstat*buf);这个函数本身没有问题,问题出在结构stat上,st_ctime在Win32下代表创建(create)时间,在Linux下代表最后修改(change)时间。FILE*fopen(constchar*path,constchar*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/TlsTlsSetValue之类的函数,在变量前加一个__declspec(thread)就行了,但是虽然在pthread里有类似的功能,却不能按这类方式实现,所以没法移植到Linux下。一样gcc也有很多扩大,是在VC或其它编译器里所没有的。

11.注意平台的特性。比如:在Win32下的DLL里面,除非明确指明为export的函数外,其它函数对外都是不可见的。而在Linux下,所有的非static的全局变量和函数,对外全部是可见的。这要特别当心,同名函数引发的问题,让你查上两天也不为过。目录分隔符,在Win32下用‘//’,在Linux下用‘/’。文本文件换行符,在Win32下用‘/r/n’,在Linux下用‘/n’,在MacOS下用‘/r’。字节顺序(大端/小端),不同硬件平台的字节顺序可能不一样。字节对齐,在有的平台(如x86)上,字节不对齐,不过速度慢一点,而有的平台(如arm)上,它完全用毛病的方式去读取数据,而且不会给你一点提示。若出问题,可能让你一点头绪都没有。

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
































白癫疯医院
白癜风的治疗



转载请注明:http://www.nydjfy.com/xxzl/646.html

  • 上一篇文章:
  •   
  • 下一篇文章: