什么时候用inttypes.h不合适?
When is it not appropriate to use inttypes.h?
C99 及更高版本提供了 inttypes.h
header,它为特定宽度的整数定义了可移植类型定义。这是比例如更强的保证。 C 的标准 int
至少 16 位宽,long int
至少 32 位宽。
假设一个项目可以使用 C99 或更高版本并且不需要特别要求 ANSI C89,是否有使用 inttypes.h
和其中定义的类型不合适的用例,尤其是因为乍一看这个库似乎是对 C 的基本 int
类型的 near-universal 改进?
C99 类型的一个问题是,尽管它们的大小是以独立于平台的方式定义的,但它们的行为却不是。例如,给定 uint16_t a=3,b=4,c=5; int x= (a > b-c)
,一些实现需要产生 1(因为 3 > -1),但其他实现需要产生 0(因为 3u < 65535u)。在许多情况下,可以通过显式屏蔽操作结果来绕过这些限制,并且在许多情况下编写代码,例如(a > (uint16_t)(b-c))
、(a > ((int)b-c)
或 (a > ((int32_t)b-c)
[取决于实际想要计算的内容] 会使意图更加清晰。
另一方面,有时整数提升会以奇怪的方式表现出来。在决定 short unsigned 类型是否应该提升为 signed 或 unsigned int 时,C89 的作者观察到,在大多数当时的实现中,有符号和无符号算术在一些特定上下文之外的行为相同,即使在以下情况下也是如此超出范围 0..INT_MAX,但一些实现试图利用标准实际上并不 要求 的事实。它可能看起来不像:
unsigned mulMod65535(uint16_t x, uint16_t y) { return (x*y) & 0xFFFF; }
应该有任何副作用,但如果 gcc 知道,例如y==65535,它将使用它来传回 x "can't" 大于 32768 的事实。有趣的是,如果函数返回 uint16_t
,当前版本的 gcc 似乎会避免这样的假设,但我不知道任何承诺未来版本不会更具侵略性的东西。
C99 及更高版本提供了 inttypes.h
header,它为特定宽度的整数定义了可移植类型定义。这是比例如更强的保证。 C 的标准 int
至少 16 位宽,long int
至少 32 位宽。
假设一个项目可以使用 C99 或更高版本并且不需要特别要求 ANSI C89,是否有使用 inttypes.h
和其中定义的类型不合适的用例,尤其是因为乍一看这个库似乎是对 C 的基本 int
类型的 near-universal 改进?
C99 类型的一个问题是,尽管它们的大小是以独立于平台的方式定义的,但它们的行为却不是。例如,给定 uint16_t a=3,b=4,c=5; int x= (a > b-c)
,一些实现需要产生 1(因为 3 > -1),但其他实现需要产生 0(因为 3u < 65535u)。在许多情况下,可以通过显式屏蔽操作结果来绕过这些限制,并且在许多情况下编写代码,例如(a > (uint16_t)(b-c))
、(a > ((int)b-c)
或 (a > ((int32_t)b-c)
[取决于实际想要计算的内容] 会使意图更加清晰。
另一方面,有时整数提升会以奇怪的方式表现出来。在决定 short unsigned 类型是否应该提升为 signed 或 unsigned int 时,C89 的作者观察到,在大多数当时的实现中,有符号和无符号算术在一些特定上下文之外的行为相同,即使在以下情况下也是如此超出范围 0..INT_MAX,但一些实现试图利用标准实际上并不 要求 的事实。它可能看起来不像:
unsigned mulMod65535(uint16_t x, uint16_t y) { return (x*y) & 0xFFFF; }
应该有任何副作用,但如果 gcc 知道,例如y==65535,它将使用它来传回 x "can't" 大于 32768 的事实。有趣的是,如果函数返回 uint16_t
,当前版本的 gcc 似乎会避免这样的假设,但我不知道任何承诺未来版本不会更具侵略性的东西。