C99标准是否保证了无符号整数的二进制表示?

3

C99 (ISO/IEC 9899:1999)

6.2.6.2/1 整数类型

填充位的值是未定义的。45) 对于有符号整数类型的有效(非trap)对象表示,其中符号位为零,则该对象表示的无符号类型的相应对象表示是有效的,并且应该表示相同的值。

对于任何整数类型,所有位都为零的对象表示应该是该类型中值为零的一个表示形式。

在C99标准中,一个整数类型的所有位都为零的对象表示形式被保证表示相应类型的值为0。但是,这是否保证底层二进制值与我们期望的相同呢?

例如:

unsigned x = 42;

通常情况下,计算机会将十进制的值 42 以二进制 101010 的形式存储在内存中。

然而,一些古怪的机器架构可能会将同样的十进制值 42 存储为二进制 011011 的形式(不一定是出于实际原因,只是因为它可以这样做)。

如果是这样的话,考虑以下使用右移操作的代码:

unsigned y = x>>1;    /* 101010>>1 or 011011>>1 */

y会持有十进制值21(二进制为10101),还是十进制值13(二进制为01101)?

C99标准是否保证无符号整数类型在位运算后的十进制表示--例如,所有机器结构上都保证右移相当于整数除以2

3个回答

3
整数的表示在标准中没有指定。
但是,>><<的行为根据位的含义而不是它们的位置进行定义。
所以>> 1将代表4的位移动到代表2的位,而不管这些位实际上在哪里。
引用C99 standard第6.5.7节:

E1 >> E2的结果是E1向右移动E2个比特位。如果E1具有无符号类型或E1具有带符号类型且为非负值,则结果的值为E1 / 2E2的商的整数部分。如果E1具有带符号类型且为负值,则得到的值是实现定义的。


1
< p > >> 运算符将移动位。在正常系统下,这意味着只是移位。但实际上,我们正在将表示位置2^3的位移动到位置2^2,无论它在哪里。

因此,在所有系统上,assert(42 >> 1 == 21)


关于您的第二个问题,是的,只要您忽略陷阱/填充位。这些显然可能不同,但通常对您来说也是不可见的。

1
你能否提供一个可以验证这些信息的参考资料? - idoby
@sharth 你的意思是 42 >> 1 == 21 吗? - Vilhelm Gray
@VilhelmGray:我就是这个意思。谢谢。 - Bill Lynch

1
标准并不保证任何关于如何在内存中物理存储事物的内容。没有这个必要。机器可以是三进制、十进制或模拟,而不是二进制。机器甚至不需要有物理位。
它所保证的关于无符号整数的唯一内容是,按位运算符将“位”作为数字的二进制位置表示的元素来影响。这些实际上是虚拟的位。它们可以直接对应于物理位(通常情况下是这样),也可以纯粹是概念性的。
“>>” 运算符保证将这些虚拟位向右移动,这意味着它总是保证将正整数值除以2。因此,对于初始值 x=42,x=x >> 1保证会在 x 中产生 21。也就是说,如果某台机器将 42 物理地表示为 011011,则该机器的编译器将需要生成改变该 42 表示形式到 21 表示形式(无论它是什么)的代码,即使后者在物理上看起来不像“向右移动”的 011011 模式。

标准要求如果 sizeof(someType)n,则 someType 类型的值可以分解为范围在 0..UCHAR_MAX 中的 n 个值,并进一步要求 UCHAR_MAX+1 是 2 的幂。虽然理论上可以使用具有十个状态存储管的机器运行 C,但必须做一些事情,使每组五个存储器从 00000 到 65535 存储一个值来表示 charshort,并且永远不要让任何五个寄存器组中的值大于或等于 65536。效率不是很高。 - supercat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接