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

问题描述 投票:49回答:5

假设您使用的是支持C99的编译器(甚至只是stdint.h,是否有任何理由不使用uint8_t这样的固定宽度整数类型?

我知道的一个原因是,在处理字符时使用char而不是使用(u)int8_t中提到的this question更为有意义。

但是,如果您打算存储数字,什么时候要使用不知道数字的大小?即在什么情况下,您想将数字存储在unsigned short中而不知道它是8位,16位还是32位,而不是使用uint16t

接着,使用固定宽度的整数或使用普通的整数类型,并且从不假设任何内容,并且在需要知道它们使用多少字节的地方使用sizeof,这是更好的做法吗?

c integer byte sizeof c99
5个回答
38
投票

实际上,存储数字而不需要知道类型的确切大小是很普遍的。我的程序中有很多数量,我可以合理地假设它们不会超过20亿,或者强迫它们不超过20亿。但这并不意味着我需要一个确切的32位类型来存储它们,我认为可以计数到至少20亿的任何类型都是可以的。

如果您要编写非常便于移植的代码,则必须牢记固定宽度类型都是可选

CHAR_BIT大于8的C99实现中,没有int8_t。该标准禁止它存在,因为它必须具有填充位,并且intN_t类型定义为没有填充位(7.18.1.1/1)。 uint8_t因此也被禁止,因为(谢谢,哦)没有uint8_t的实现不允许定义int8_t

因此,在非常可移植的代码中,如果您需要一个能够容纳最多127个值的带符号类型,则应根据是否要询问而使用signed charintint_least8_tint_fast8_t中的一种编译器使其:

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

对于最大值为255的无符号类型,unsigned charunsigned intuint_least8_tuint_fast8_t也是一样。

如果您需要使用非常便于移植的代码进行256模运算,则可以自己获取模数,屏蔽位或使用位域进行游戏。

实际上,大多数人不需要编写可移植的代码。目前,CHAR_BIT > 8仅出现在专用硬件上,并且您的通用代码不会在其上使用。当然,将来可能会改变,但是如果确实如此,我怀疑有太多代码对Posix和/或Windows作了假设(两者均保证CHAR_BIT == 8),那么处理代码的不可移植性将是其中之一。将代码移植到该新平台的一小部分工作。任何此类实现可能都将不得不担心如何连接到Internet(以八位位组交易),而这早在它担心如何使您的代码正常运行时就很容易了:-)

[如果您仍然以为CHAR_BIT == 8,那么我认为除了希望代码在C89中工作之外,没有其他特殊原因可以避免(u)int8_t。即使在C89中,为特定的实现查找或编写stdint.h版本也不难。但是,如果您可以轻松编写代码以仅要求该类型可以容纳255,而不是要求它不能容纳256,那么您也可以避免依赖于CHAR_BIT == 8


12
投票

尚未提及的一个问题是,虽然使用固定大小的整数类型将意味着如果编译器对intlong使用不同的大小,则变量大小不会改变。第四,并不一定要保证代码在具有各种整数大小的计算机上的行为相同,即使[定义了大小。

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

我不知道有多少代码依赖于这样的事实:即使在没有类型转换的情况下,也需要包装涉及无符号类型的表达式的中间结果(恕我直言,如果需要包装行为,程序员应该包括一个类型转换)[ C0]),但目前该标准不允许有任何回旋余地。我想知道,如果在没有类型转换或类型强制的情况下,至少

permited

编译器将操作数提升为更长的整数类型的规则会带来什么问题?给定(uint32_t)(i-1) > 5,就需要像uint32_t i,j这样的分配来消除溢出,就像j = (i+=1) >> 1;一样,但是j = (uint32_t)(i+1) >> 1;不会]?或者,就此而言,对于编译器制造商来说,要保证其中间结果都可以适合最大有符号类型且不涉及非恒定量右移的任何整数类型表达式将很难产生相同的结果结果是否好像所有计算都针对该类型?在我看来,在j = (i+1)>>1为32位的计算机上,这似乎很讨厌:uint64_t a,b,c;...&=〜0x40000000;b&=〜0x80000000;c&=〜0x100000000;
清除inta各一位,但清除c的前33位;大多数编译器都不会暗示第二个表达式有什么“不同”。

7
投票
确实,标准整数类型的宽度可以从一个平台更改为另一平台,但不能更改为最小的

width。

例如,C标准指定b至少为int,并且16-bit至少为long宽。

如果存储对象时没有大小限制,则可以将其用于实现。例如,如果最大符号值适合32-bit,则可以只使用16-bit。然后,您可以让实现的最终含义是实现所针对的体系结构的自然int宽度。


4
投票
仅在假设宽度时才使用固定宽度类型。

intuint8_t在大多​​数平台上都是相同的,但并非在所有平台上都相同。使用unsigned char强调一个事实,即您假设一个具有8位uint8_t的体系结构,并且不会在其他体系结构上进行编译,因此这是一项功能。

否则,我将使用“语义” char,例如typedefsize_tuintptr_t,因为它们可以更好地反映您对数据的想法。我几乎从不直接使用基本类型,ptrdiff_t仅用于错误返回,并且我不记得曾经使用过int

Edit:仔细阅读C11之后,我得出结论,即使short存在,它也必须是uint8_t,即使该类型是无符号的,也不能只是unsigned char。这来自7.20.1 p1中的要求,即所有charintN_t必须为corresponding有符号和无符号类型。此类唯一的字符类型对是uintN_tsigned char


3
投票
代码应向临时读者(和程序员自己)揭示重要的内容。它只是一些整数还是

无符号整数甚至是有符号整数。大小也一样。缺省情况下某些变量为16位对算法真的重要吗?还是仅仅是不必要的微管理和失败的优化尝试?

这就是使编程成为一门艺术-展示重要的东西。
© www.soinside.com 2019 - 2024. All rights reserved.