有没有什么理由不使用固定宽度的整数types(例如uint8_t)?

假设你正在使用一个支持C99的编译器(甚至只是stdint.h),有什么理由不使用固定宽度的整数types,如uint8_t?

我知道的一个原因是,在处理字符而不是使用(u)int8_t s时,使用char s更有意义,正如这个问题所提到的。

但是,如果你打算存储一个数字,你想什么时候使用一个你不知道它有多大的types呢? 也就是说,在什么情况下,你要存储一个数字在一个unsigned short而不知道是8,16甚至32位,而不是使用uint16t

接下来的是,使用固定宽度的整数或使用正常的整数types是不是更好的做法,只要不需要知道它们使用了多less个字节,就不要假设任何东西和sizeof

存储号码实际上是很常见的,不需要知道types的确切大小。 我的程序中有很多数量可以合理地假定不会超过20亿,或者强制他们不这样做。 但是这并不意味着我需要一个精确的32位types来存储它们,任何可以计数到至less20亿的types对我来说都是很好的。

如果您正在编写非常便携的代码,则必须牢记固定宽度types都是可选的

CHAR_BIT大于8的C99实现中,没有int8_t 。 标准禁止它存在,因为它必须有填充位,而intN_ttypes被定义为没有填充位(7.18.1.1/1)。 uint8_t因此也被禁止,因为(谢谢,ouah)一个实现不允许定义uint8_t没有int8_t

所以,在非常便携的代码中,如果你需要一个能够保持127的值的签名types,那么你应该使用signed charintint_least8_t或者int_fast8_t根据你是否要求编译器做出这个:

  • 在C89工作( signed charint
  • 在算术expression式中避免令人惊讶的整数提升( int
  • 小( int_least8_tsigned char
  • 快( int_fast8_tint

对于无符号types( unsigned charunsigned intunsigned intuint_least8_tuint_fast8_tuint_least8_t uint_fast8_t

如果你需要用非常便携的代码进行模256运算,那么你可以自己来取模,屏蔽比特,或者用位域来玩游戏。

在实践中,大多数人从不需要编写可移植的代码。 目前CHAR_BIT > 8只在专用硬件上出现,你的通用代码不会被使用。 当然,这可能会在将来改变,但如果我怀疑有太多的代码,使Posix和/或Windows的假设(这两个保证CHAR_BIT == 8 ),处理您的代码的不可移植性将是将代码移植到新平台上的一小部分工作。 任何这样的实现可能都会担心如何连接到互联网(以八位字节为单位),而不必担心如何让代码启动和运行:-)

如果你假设CHAR_BIT == 8 ,那么我不认为有什么特别的理由可以避免(u)int8_t而不是你想让代码在C89中工作。 即使在C89中,为特定实现find或写入stdint.h版本也不是那么困难。 但是如果你可以很容易地编写你的代码,只需要这个types可以保持255 ,而不是要求它不能保持256 ,那么你可以避免依赖于CHAR_BIT == 8

还没有提到的一个问题是,尽pipe使用固定大小的整数types将意味着如果编译器对intlong等使用不同大小的variables的大小不会改变,那么它将不会必然保证代码在具有各种整数大小的机器上将performance相同, 即使在定义大小时也是如此

例如,给定的声明uint32_t i;i为零时,expression式(i-1) > 5的行为将取决于uint32_t是否小于int 。 在系统中,如int是64位(和uint32_t是类似long short ),variablesi会被提升为int ; 减法和比较将按照有符号进行(-1小于5)。 在int为32位的系统上,减法和比较将作为unsigned int执行(减法将产生一个非常大的数字,大于五)。

我不知道有多less代码依赖于涉及无符号types的expression式的中间结果即使在没有types转换时也需要包装(恕我直言,如果需要包装行为,程序员应该包含一个types转换) (uint32_t)(i-1) > 5 ),但标准目前不允许有余地。 我想知道如果一个规则至less允许编译器在没有types转换或types强制的情况下将操作数提升为更长的整型(例如给定uint32_t i,jj = (i+=1) >> 1; 将需要切断溢出,就像j = (uint32_t)(i+1) >> 1; ,但是j = (i+1)>>1不会]? 或者,对于编译器制造商来说,要保证任何中间结果都能够符合最大符号types并且不涉及非恒定数量右移的整型expression式将会产生同样的结果结果就好像所有的计算都是在这种types上执行的? 对于我来说,在int为32位的机器上似乎相当恶劣:

   uint64_t a,b,c;
   ...
   a&=〜0x40000000;
   b&=〜0x80000000;
   c&=〜0x100000000;

清除aca ,但清除b的前33位; 大多数编译器都不会暗示关于第二个expression式的任何东西都是“不同的”。

确实,标准整数types的宽度可能会从一个平台变到另一个平台,而不是最小的宽度

例如,C标准指定一个int至less是16-bit而一个long至less是32-bit位宽。

如果在存储对象时没有一定的大小限制,则可以将其放到实现中。 例如,如果您的最大符号值将适合在16-bit您可以使用一个int 。 然后让实现对实现所针对的体系结构的自然宽度进行最后的说明。

在对宽度进行假设时,只应使用固定宽度types。

uint8_tunsigned char在大多数平台上都是一样的,但不是全部。 使用uint8_t强调的事实,你假设一个8位char的架构,不会在别人编译,所以这是一个function。

否则,我会使用“语义” uintptr_t ptrdiff_t ,如size_tuintptr_tptrdiff_t因为它们反映了您对数据的更好的想法。 我几乎从来没有直接使用基types, int只是为了返回错误,我不记得使用过short

编辑:仔细阅读C11后,我认为uint8_t ,如果存在,必须是unsigned char ,不能只是char即使该types是无符号的。 这来自7.20.1 p1中的要求,所有的intN_tuintN_t必须是相应的有符号和无符号types。 字符types唯一的这种对是有signed charunsigned char

代码应该向临时读者(和程序员他/她自己)揭示什么是重要的。 它只是一些整数或无符号整数 ,甚至有符号整数 。 大小也一样。 对于algorithm来说,一些variables默认是16位,这真的很重要吗? 或者,这只是不必要的微观pipe理和失败的优化尝试?

这是编程艺术的一个重要方面。