假设您使用的是支持C99的编译器(甚至只是stdint.h,是否有任何理由不使用uint8_t这样的固定宽度整数类型?
我知道的一个原因是,在处理字符时使用char
而不是使用(u)int8_t
中提到的this question更为有意义。
但是,如果您打算存储数字,什么时候要使用不知道数字的大小?即在什么情况下,您想将数字存储在unsigned short
中而不知道它是8位,16位还是32位,而不是使用uint16t
?
接着,使用固定宽度的整数或使用普通的整数类型,并且从不假设任何内容,并且在需要知道它们使用多少字节的地方使用sizeof
,这是更好的做法吗?
实际上,存储数字而不需要知道类型的确切大小是很普遍的。我的程序中有很多数量,我可以合理地假设它们不会超过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 char
,int
,int_least8_t
或int_fast8_t
中的一种编译器使其:
signed char
或int
)int
)int_least8_t
或signed char
)int_fast8_t
或int
)对于最大值为255的无符号类型,unsigned char
,unsigned int
,uint_least8_t
和uint_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
。
尚未提及的一个问题是,虽然使用固定大小的整数类型将意味着如果编译器对int
,long
使用不同的大小,则变量大小不会改变。第四,并不一定要保证代码在具有各种整数大小的计算机上的行为相同,即使[定义了大小。
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;清除int
和a
各一位,但清除c
的前33位;大多数编译器都不会暗示第二个表达式有什么“不同”。
width。
例如,C标准指定b
至少为int
,并且16-bit
至少为long
宽。如果存储对象时没有大小限制,则可以将其用于实现。例如,如果最大符号值适合32-bit
,则可以只使用16-bit
。然后,您可以让实现的最终含义是实现所针对的体系结构的自然int
宽度。
int
和uint8_t
在大多数平台上都是相同的,但并非在所有平台上都相同。使用unsigned char
强调一个事实,即您假设一个具有8位uint8_t
的体系结构,并且不会在其他体系结构上进行编译,因此这是一项功能。
否则,我将使用“语义” char
,例如typedef
,size_t
,uintptr_t
,因为它们可以更好地反映您对数据的想法。我几乎从不直接使用基本类型,ptrdiff_t
仅用于错误返回,并且我不记得曾经使用过int
。
Edit:仔细阅读C11之后,我得出结论,即使short
存在,它也必须是uint8_t
,即使该类型是无符号的,也不能只是unsigned char
。这来自7.20.1 p1中的要求,即所有char
和intN_t
必须为corresponding有符号和无符号类型。此类唯一的字符类型对是uintN_t
和signed char
。
无符号整数甚至是有符号整数。大小也一样。缺省情况下某些变量为16位对算法真的重要吗?还是仅仅是不必要的微管理和失败的优化尝试?
这就是使编程成为一门艺术-展示重要的东西。