今天聊聊C++的可移植性问题。如果你平时使用C++进行开发,并且你对C++的可移植性问题不是非常清楚,那么我建议你看看这个系列。即使你目前没有跨平台开发的需要,了解可移植性方面的知识对你还是很有帮助的。
C++的可移植性这个话题很大,包括了编译器、操作系统、硬件体系等很多方面,每一个方面都有很多内容。鉴于本人能力、精力都有限,只能介绍每一个方面最容易碰到的问题,供大伙儿参考。
后面我会分别从编译器、C++语法、操作系统、第三方库、辅助工具、开发流程等方面进行介绍。
编译器
在跨平台的开发过程中,很多问题都和编译器有关。因此我们先来聊聊编译器相关的问题。
编译器的选择
首先,GCC是优先要考虑支持的,因为几乎所有操作系统平台都有GCC可用。它基本上成了一个通用的编译器了。如果你的代码在A平台的GCC能够编译通过,之后拿到B平台用类似版本的GCC编译,一般也不会有太大问题。因此GCC是肯定要考虑支持的。
其次,要考虑是否支持本地编译器。所谓本地编译器就是操作系统厂商自产的编译器。例如:相对于Windows的本地编译器就是Visual C++。相对于Solaris的本地编译器就是SUN的CC。如果你对性能比较敏感或者想用到某些本地编译器的高级功能,可能就得考虑在支持GCC的同时也支持本地编译器。
编译警告
编译器是程序员的朋友,很多潜在的问题(包括可移植性),编译器都是可以发现并给出警告的,如果你平时注意这些警告信息,可以减少很多麻烦。因此我强烈建议:
1把编译器的警告级别调高;
2不要轻易忽略编译器的警告信息。
交叉编译器
交叉编译器的定义参见“维基百科”。通俗地说,就是在A平台上编译出运行在B平台上的二进制程序。假设你要开发的应用是运行在Solaris上,但是你手头没有能够运行Solaris的SPARC机器,这时候交叉编译器就可以派上用场了。一般情况下都使用GCC来制作一个交叉编译器,限于篇幅,这里就不深入聊了。有兴趣的同学可以参见“这里”。
异常处理
上一个帖子“语法”由于篇幅有限,没来得及聊异常,现在把和异常相关的部分单独拿出来说一下。
小心new分配内存失败
早期的老式编译器生成的代码,如果new失败会返回空指针。我当年用的Borland C++ 3.1似乎就是这样的,现在这种编译器应该不多见了。如果你目前用的编译器还有这种行为,那你就惨了。你可以考虑重载new操作符来抛出 bad_alloc异常,便于进行异常处理。
稍微新式一点的编译器,就不是仅仅返回空指针了。当new操作符发现内存告急,按照标准的规定(参见C++ 03标准18.4.2章节),它应该去调用new_handler函数(原型为typedef void (*new_handler)();)。标准建议new_handler函数干如下三件事:
1、设法去多搞点内存来;
2、抛出bad_alloc异常;
3、调用abort()或者exit()退出进程。
由于new_handler函数是可以被重新设置的(通过调用set_new_handler),所以上述的行为它都可能有。
综上所述,new分配内存失败,有可能三种可能:
1、返回空指针;
2、抛出异常;
3、进程立即终止。
如果你希望你的代码具有较好的移植性,你就得把这三种情况都考虑到。
慎用异常规格
异常规格在我看来不是一个好东西,不信可以去看看《C++ Coding Standards - 101 Rules, Guidelines & Best Practices》的第75条。(具体有哪些坏处以后专门开一个C++异常和错误处理的帖子来聊)言归正传,按照标准(参见03标准18.6.2章节),如果一个函数抛到外面的异常没有包含在该函数的异常规范中,那么应该调用unexcep
C++的可移植性和跨平台开发(长文)
最新推荐文章于 2024-10-05 23:41:51 发布
本文探讨C++的可移植性问题,包括编译器选择、编译警告、交叉编译器、异常处理等方面的注意事项。强调了GCC作为通用编译器的重要性,以及在跨平台开发中如何处理编译器差异、异常行为和硬件体系相关问题。此外,还涉及了文件系统、文本文件的回车/换行处理、动态库和多线程编程的挑战。
摘要由CSDN通过智能技术生成