C99 标准是不是保证 unsigned int 的二进制表示?
Posted
技术标签:
【中文标题】C99 标准是不是保证 unsigned int 的二进制表示?【英文标题】:Does the C99 standard guaranteed the binary representation of unsigned int?C99 标准是否保证 unsigned int 的二进制表示? 【发布时间】:2013-06-07 08:51:26 【问题描述】:C99 (ISO/IEC 9899:1999)
6.2.6.2/1 整数类型
未指定任何填充位的值。45) 有效 (非陷阱)有符号整数类型的对象表示,其中 符号位为零是对应的有效对象表示 无符号类型,代表相同的值。
对于任何整数 类型,所有位为零的对象表示应为 该类型中值零的表示形式。
在 C99 标准中,保证所有位都为零的整数类型表示相应类型中的值 0
。但是,这能保证底层的二进制值是我们所期望的吗?
例如:
unsigned x = 42;
我们通常希望机器将此十进制 42
值作为二进制 101010
值存储在内存中。
但是,某些古怪的机器架构是否可以存储与二进制 011011
值相同的十进制 42
值(不一定出于实际原因,而仅仅是因为它可以)?
如果是这样,请考虑使用右移操作的以下代码:
unsigned y = x>>1; /* 101010>>1 or 011011>>1 */
y
会保留十进制值 21
(10101
二进制)还是十进制值 13
(01101
二进制)?
C99 标准是否对按位运算后无符号整数类型的十进制表示作任何保证——例如在所有机器架构上,右移是否保证等于2
的整数除法?
【问题讨论】:
【参考方案1】:标准中没有指定整数的表示。
但是>>
和<<
的行为是根据位的含义定义的,而不是它们的位置。
所以>> 1
将代表 4 的位移动到代表 2 的位上,而不管这些位实际在哪里。
引用C99 standard 6.5.7 节:
E1 >> E2 的结果是E1 右移E2 位位置。如果 E1 具有无符号类型 或者如果 E1 具有带符号类型和非负值,则结果的值是 E1 / 2E2 商的整数部分.如果 E1 具有带符号类型和负值,则结果值是实现定义的。
【讨论】:
【参考方案2】:>>
运算符将移动位。在正常系统下,这意味着只是转移它们。但实际上,我们将代表位置2^3
的位移动到位置2^2
,无论它在哪里。
所以在所有系统上,assert(42 >> 1 == 21)
。
至于你的第二个问题,是的,只要你忽略陷阱/填充位。这些显然可能不同,但您通常也看不见。
【讨论】:
您能在可以验证此信息的地方发布参考吗? @sharth 你的意思是42 >> 1 == 21
?
@VilhelmGray:我是认真的。谢谢。【参考方案3】:
该标准不保证事物在内存中的物理存储方式。没有必要这样做。该机器可以是三进制、十进制或物理级别的模拟,而不是二进制。机器甚至不需要物理位。
它对 unsigned int 的所有保证是按位运算符影响“位”作为数字的二进制位置表示的元素。这些实际上是 virtual 位。它们可以直接对应于物理位(在实践中通常是这种情况),也可以是纯粹的概念。
>>
运算符保证将这些虚拟位向右移动,这意味着它始终保证将正整数值除以 2。因此,对于 x = 42
的初始值,此 x = x >> 1
保证在x
中生成21
。这意味着,如果某些机器将42
物理表示为011011
,则该机器的编译器将需要生成代码,将42
的表示更改为21
的表示(不管它是什么),甚至如果在物理上后者看起来不像“右移”011011
模式。
【讨论】:
标准要求如果sizeof(someType)
是n
,则someType
类型的值可以分解为0..UCHAR_MAX
范围内的n
值,并进一步要求UCHAR_MAX+1
是二的幂。虽然理论上可以使用具有十态存储管的机器来运行 C,但必须做一些事情,让每组五个存储一个从 00000 到 65535 的值来表示 char
或 short
,并且永远不会有任何五个寄存器组的值是 65536 或更高。效率不高。以上是关于C99 标准是不是保证 unsigned int 的二进制表示?的主要内容,如果未能解决你的问题,请参考以下文章
省略数据类型(例如“unsigned”而不是“unsigned int”)