C ++跨平台代码

时间:2010-08-10 17:10:14

标签: c++ cross-platform

我们将在我们的小团队中开始一个新项目:

  • 这是一个将由我们的其他项目(在Linux和Windows中)使用的库。
  • 它不依赖于平台(它不使用任何系统调用或类似的东西)。
  • 必须在各种平台上编译(至少包括Windows和Linux)。

不幸的是,我们的开发人员没有在Windows以外的任何平台上编写任何代码! 因此,我必须向他们提供“类似代码”代码不是这样的“列表,因此代码将保持跨平台。

任何指导?

7 个答案:

答案 0 :(得分:10)

提高可移植性的一种方法是在两个平台上使用相同的编译器GCC。如果您也使用相同的编译器版本,则可能会避免大多数(如果不是全部)C ++语言和标准库不兼容。您也可以使用相同的构建工具,例如GNU make,这意味着两个平台上的构建过程都是相同的。

至于平台不兼容性 - 请检查其代码是否包含类似的内容:

#include <windows.h>
#include <unistd.h>
#include <sys/almost_anything.h>

除非通过条件编译完成。

答案 1 :(得分:7)

确保在所有平台上都有自动构建过程,并编写单元和自动功能测试。如果可能的话,运行自动夜间构建和测试。在编写跨平台库时,这一点非常重要。

我会做其他一个答案的反面(不是我认为这是错误的,只是一种不同的方法)并且如果你可以选择你的平台使它们尽可能不同。例如,在unix上创建一个32位MCVC和另一个64位gcc。如果您可以进行自动化测试和构建,那么这将很快显示可移植性问题。

如果可能的话,有些开发人员在一个平台上工作而在另一个平台上工作,而不是在一个平台上完成代码,然后将其“移植”到另一个平台上。这样他们就可以很快地了解当他们的同事过来抱怨他们弄坏了什么时不该做什么。

技术上需要注意的事项是

  • 不要假设整数是32位
  • 不要假设char已签名或未签名
  • 不要假设字符是ASCII
  • 不要假设任何有关数据字节顺序或对齐的内容
  • 最小化指针算术。当你做出失败的假设时,你只会弄错。
  • 请记住,文件和目录名称在不同平台上的工作方式不同。如果你只需要移植到windows和unix,你可能会厌倦它,但是一旦你移植到两个平台,那么下一个端口可能是z系列或VMS,这些东西的工作方式完全不同。

答案 2 :(得分:6)

最重要的是:在所有支持的平台上运行自动构建和测试,以便立即获取大多数非便携式(或只是错误的)代码。

语言本身,标准库和Boost应该可以移植到任何广泛使用的平台(当然是现代版本的Linux / GCC和Windows / MSVC)。怀疑任何以.h结尾的系统头文件,并在决定使用它们之前检查其他库的可移植性。

维护一份您遇到的所有不兼容的文件,希望您只会犯下一次错误。

答案 3 :(得分:5)

告诉他们不要使用Windows API,他们应该好好去。

我还建议增加你的警告/错误级别,如果在Visual Studio中开发,因为它会阻止你做一些gcc(通常)不允许的事情,假设你正在使用gcc来编译Linux 。您还可以在项目设置中禁用Visual Studio扩展。

显然,如果有人需要使用特定于平台的东西,他们应该使用定义来替换特定于平台的代码,具体取决于它正在编译的平台。

答案 4 :(得分:2)

尽可能多地编译编译器,即使只在有限数量的平台上编译。在我的头顶,VC,gcc,intel,pgi。如果你可以获得其中一些版本的旧版本,那也会有所帮助。所有开发人员都不需要使用这些,但每晚运行它们,结果可供所有开发人员使用。在问题出现时更容易解决问题,而不是在尝试发布时解决所有问题。

答案 5 :(得分:1)

一些建议:

  • 使用static_cast<>dynamic_cast<>const_cast<>代替C风格的演员表。如果必须使用reinterpret_cast<>,请查看它,并通过仔细的单元测试来包围该代码。 (这条规则的要点是禁止巧妙的笨拙和依赖于尺寸或对齐。)

  • 仅使用现代标准C ++库:没有像(brrr!)MFC及其CString这样的特定于MS的库。

您可以添加一些建议here,但请注意,对于合理的现代编译器,有些建议有些过于悲观(例如,关于临时对象的建议#16,以及#18与STL部分直接冲突)的图书馆)。

答案 6 :(得分:0)

从在Windows开发人员中开发Linux的经验来看,正常的主要问题(如果你真的没有像你说的那样使用平台相关代码)只是#include文件名中的区分大小写。除此之外,你会发现默认情况下,gcc比MSVC更严格,所以你可能需要收紧一些东西,但它们通常很简单。

需要注意的一点是std::map::erase does not return an iterator