编写可移植的C程序 - 需要考虑哪些事项?

时间:2010-02-20 20:06:24

标签: c portability

对于大学的项目,我需要扩展现有的C应用程序,该应用程序最终将运行在各种商业和非商业unix系统(FreeBSD,Solaris,AIX等)上。

当我想编写一个最便携的C程序时,我需要考虑哪些事项?

7 个答案:

答案 0 :(得分:22)

我能给出的最好建议是每天搬到不同的平台,随时进行测试 这将使平台差异像拇指一样突出,并同时教你可移植性问题。

保存跨平台测试结束,将导致失败。

除此之外

  • 整数大小可能会有所不同。
  • 浮点数可能会有不同的表示。
  • 整数可以有不同的字节序。
  • 编辑选项可能有所不同。
  • 包含文件名可能会有所不同。
  • 位字段的实现会有所不同。

通常最好将编译器警告级别设置为尽可能高, 看到编译器可以抱怨的各种事情。

答案 1 :(得分:7)

我曾经编写C实用程序,然后我会支持16位到64位架构,包括一些60位机器。它们包括至少三种“字节序”,不同的浮点格式,不同的字符编码和不同的操作系统(尽管Unix占主导地位)。

  1. 尽可能接近标准C。对于不属于标准的函数/库,请使用尽可能广泛支持的代码库。例如,对于网络,使用BSD套接字接口,使用零级或最小级别的套接字选项,带外信令等。为了以最少的人员支持大量不同的平台,您将不得不停留具有普通的香草功能。
  2. 非常了解标准所保证的内容,以及典型的实施行为。例如,指针的大小不一定与整数相同,指向不同数据类型的指针可能具有不同的长度。如果您必须依赖于实现假设,请将其记录下来。 Lint,或--strict,或者你的开发工具集所具有的等价物,在这里至关重要。
  3. 页眉文件是你的朋友。使用实现定义的宏和常量。使用标题定义和#ifdef来帮助隔离那些需要涵盖少量备选方案的实例。
  4. 不要假设当前平台使用EBCDIC字符和压缩十进制整数。有相当数量的ASCII - 两个补充机器。 : - )
  5. 有了这些,如果你避免多次写东西和#ifdef代码的主要部分的诱惑,你会发现跨不同平台的编码和测试有助于更快地发现错误。你最终会制作出更有纪律,可理解,可维护的程序。

答案 2 :(得分:4)

  1. 使用至少两个编译器。
  2. 建立一个持续构建系统,最好建立在各种目标平台上。
  3. 如果您不需要工作在非常低级别,请尝试使用一些提供抽象的库。您不太可能找不到为您需要的东西提供良好抽象的第三方库。例如,对于网络和通信,有ACE。 Boost(例如文件系统)也被移植到几个平台。这些是C ++库,但也可能有其他C库(如curl)。
  4. 如果你必须在低级别工作,请注意平台偶尔会有不同的行为,即使在像posix那样它们应该具有相同行为的东西上也是如此。您可以查看上面库的源代码。

答案 3 :(得分:4)

您可能需要及时了解的一个特定问题(例如,如果您的数据文件可以跨平台工作)endianness

在不同体系结构的二进制级别上,数字的表示方式不同。 Big-endian系统首先排序最重要的字节,而little-endian系统首先排序最不重要的字节。

如果以一个字节顺序将一些原始数据写入文件,然后在具有不同字节顺序的系统上读回该文件,则显然会出现问题。

您应该能够在sys/param.h的大多数系统上在编译时获得字节序。如果需要在运行时检测它,一种方法是使用intchar的并集,然后将char设置为1并查看{{1}的值} has。

答案 4 :(得分:2)

这是一个很长的清单。最好的办法是阅读例子。例如source of perl。如果你看一下perl的来源,你会看到一个巨大的构建头文件的过程,它处理大约50个平台问题。

读它并哭泣或借用。

答案 5 :(得分:1)

列表可能很长,但它并不像支持Windows和MSDOS那么长。这对许多公用事业来说很常见。

通常的技术是将核心算法模块与处理操作系统的模块分开 - 基本上是分层抽象的策略。

相比之下,在几种unix之间进行区分是相当简单的。坚持使用所有使用相同RTL名称的功能,或者查看支持的平台的多数约定以及例外中的#ifdef

答案 6 :(得分:1)

对于您使用的任何库函数,请继续参考POSIX标准。标准的某些部分是模糊的,一些系统返回不同类型的错误代码。这将帮助您主动找到那些真正难以找到稍微不同的实现错误。