避免在平台无关的代码中使用实现定义类型

7

我刚开始着手一个大项目,该项目应该是平台无关的,但实际上使用了一些实现定义的类型,例如char

这已经引起了一些问题,因为对于某些设备,char默认为signed,而对于其他设备则为unsigned

我希望找到一种解决方案,以避免在必须平台无关的代码中使用实现定义的类型。

  1. 最好的解决方案是什么?重新定义所有的char变量为unsigned char(或signed char),使用编译器参数(例如:-funsigned-char),typedefs,还是其他方法?
  2. 是否有其他类型,标准没有定义它们是有符号还是无符号?

1
https://en.wikibooks.org/wiki/C_Programming/inttypes.h - Iłya Bursov
char 的符号性不是平台定义的,而是编译器定义的。因此,列在 1 中的任何一个都可以。但我会选择显式类型声明。2)对于标准内置类型来说,不需要。 - Eugene Sh.
2
@EugeneSh。"平台"通常也包括编译器 :) - P.P
@P.P. 是的,我的意思是它是完全由编译器定义的。 - Eugene Sh.
2
并非总是如此。根据C标准的第7.20.1.1节“精确宽度整数类型”,第3段:“这些类型是可选的。”但是,它后面跟着“然而,如果实现提供具有8、16、32或64位宽度、没有填充位且(对于有符号类型)具有二进制补码表示的整数类型,则应定义相应的typedef名称。”因此,常见系统确实需要具有固定宽度的整数类型。 - Andrew Henle
显示剩余4条评论
3个回答

6
在理论上,答案非常简单:
始终使用类型用于它们的预期目的。例如,对于诸如数组大小之类的东西,您需要实现定义的类型,因为在不同的平台上,此类大小的上限将是不同的。指针也是如此。对于固定大小类型的需求,C已经在stdint.h中提供了适当的typedef
以下是一个不完整的“应该使用什么”列表:
  • 对于任何不需要固定大小并且永远不会超出16位范围的整数,请使用(unsignedint
  • 对于字符,请使用char,在处理将字符存储在int中的库函数时,请使用intunsigned char强制转换。
  • 与对象大小相关的任何事物,例如数组索引,请使用size_t
  • 每当您需要将指针的存储在整数中时,请使用uintptr_t
  • 对于需要固定位数且不应根据目标平台而更改的任何整数,请使用intX_t/uintX_t(其中X是位数)
  • 如果类型的大小实际上更大没有关系,请改用int_leastX_t/uint_leastX_t。无法寻址八位字节的实现可能不会提供例如uint8_t,但它提供具有更多位的uint_least8_t

但这可能会为 uint_least8_t 提供更多的位数。但是,C 标准要求使用 uint_least8_t。如果平台不符合标准,实际上在不使用特定于平台的 typedef 的情况下实现可移植性可能是不可能的。 - Andrew Henle
@AndrewHenle 好的,我会把它改成更精确的东西...算了,我就把“可能”去掉吧——你是正确的,在这里讨论不符合至少C99的实现没有多大意义。 - user2371524

1
经典的方法是使用自己定义的 typedef 类型,并让您的 make/autoconf 等检测平台特性并为您设置 typdefs。

这是一种老式的做法。但是维护自己的typedefs会带来很大的不必要的麻烦。相反,使用<stdint.h>中的标准类型:int8_tuint16_t等。 - Steve Summit
我本来想说那句话,但这取决于你拥有哪些编译器以及它们是否支持这些标准(我知道所有现代编译器都应该支持)。此外,他可能需要的类型可能没有被涵盖。 - pm100

0

关于这个问题有两种观点:

  1. 永远不要使用“普通”类型,如intchar,因为你永远无法知道它们的大小。始终使用固定大小的类型,例如在<stdint.h>中定义的类型。
  2. 尽可能使用“普通”类型,如intchar,因为它们应该始终与您机器上的本地类型匹配。了解它们的保证和不保证的内容,以便您可以选择适当的类型--也就是说,有时您需要long intunsigned intsize_t或其他类型。在那些(希望很少见的)情况下,当您绝对需要一个精确大小的类型时,请使用在<stdint.h>中定义的类型。

事实证明,这是一个古老的问题,一直争论不休,没有一个被广泛认可的答案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接