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 会保留十进制值 2110101 二进制)还是十进制值 1301101 二进制)?

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 的值来表示 charshort,并且永远不会有任何五个寄存器组的值是 65536 或更高。效率不高。

以上是关于C99 标准是不是保证 unsigned int 的二进制表示?的主要内容,如果未能解决你的问题,请参考以下文章

省略数据类型(例如“unsigned”而不是“unsigned int”)

使用 GLuint 而不是 unsigned int 有啥好处?

vscode支持c99标准

unsigned int 与 size_t

c语言读取unsigned int

__int64 在 32 位机器上?