【发布时间】:2011-05-27 09:47:42
【问题描述】:
我有很多对无符号整数执行按位运算的代码。我编写代码时假设这些操作是在没有任何填充位的固定宽度整数上进行的。例如一个 32 位无符号整数数组,其中所有 32 位可用于每个整数。
我希望让我的代码更具可移植性,并且我专注于确保我是 C89 compliant(在这种情况下)。我遇到的问题之一是可能的填充整数。举个极端的例子,取自GMP manual:
但是,在 Cray 矢量系统上,可能会注意到 short 和 int 始终存储在 8 个字节中(
sizeof表示这一点)但仅使用 32 或 46 位。 nails 功能可以解决这个问题,例如传递8*sizeof(int)-INT_BIT。
我还在其他地方读到过这种类型的填充。实际上,我昨晚读到了 SO 上的一篇文章(请原谅,我没有链接,我将从记忆中引用类似的内容)如果你有一个带有 60 个可用位的双精度位,那么其他 4 个可以用于填充,这些填充位可以用于某些内部目的,因此它们不能被修改。
假设我的代码是在一个平台上编译的,其中 unsigned int 类型的大小为 4 个字节,每个字节为 8 位,但最重要的 2 位是填充位。 UINT_MAX 在这种情况下会是 0x3FFFFFFF (1073741823) 吗?
#include <stdio.h>
#include <stdlib.h>
/* padding bits represented by underscores */
int main( int argc, char **argv )
{
unsigned int a = 0x2AAAAAAA; /* __101010101010101010101010101010 */
unsigned int b = 0x15555555; /* __010101010101010101010101010101 */
unsigned int c = a ^ b; /* ?? __111111111111111111111111111111 */
unsigned int d = c << 5; /* ?? __111111111111111111111111100000 */
unsigned int e = d >> 5; /* ?? __000001111111111111111111111111 */
printf( "a: %X\nb: %X\nc: %X\nd: %X\ne: %X\n", a, b, c, d, e );
return 0;
}
- 用填充位异或两个整数是否安全?
- 我不会对填充位进行异或吗?
我在 C89 中找不到这种行为。
此外,c 变量是否保证为 0x3FFFFFFF,或者例如,如果 a 或 b 中的两个填充位都打开,c 是否会是 0xFFFFFFFF?
d 和 e 的问题相同。我是否通过移位来操作填充位?
我希望在下面看到这一点,假设 32 位,其中 2 个最高有效位用于填充,但我想知道这样的事情是否得到保证:
a: 2AAAAAAA
b: 15555555
c: 3FFFFFFF
d: 3FFFFFE0
e: 01FFFFFF
填充位总是最高有效位还是最低有效位?
编辑 2010 年 12 月 19 日下午 5 点 EST:Christoph 回答了我的问题。谢谢!
我还问过(上面)填充位是否总是最重要的位。这在 C99 标准的基本原理中被引用,答案是否定的。我玩得很安全,并假设 C89 也是如此。以下是 C99 基本原理对第 6.2.6.2 节(整数类型的表示)所说的具体内容:
用户可以在无符号整数类型中访问填充位。例如,假设一台机器使用一对 16 位的 short(每个都有自己的符号位)组成一个 32 位的 int,并且在这个 32 位的 int 中使用时,忽略低位 short 的符号位。然后,作为 32 位有符号整数,有一个填充位(在 32 位中间)在确定 32 位有符号整数的值时会被忽略。但是,如果这个 32 位项被视为 32 位无符号整数,则该填充位对用户程序是可见的。 C 委员会被告知有一台机器可以以这种方式工作,这就是在 C99 中添加填充位的原因之一。
脚注 44 和 45 提到奇偶校验位可能是填充位。委员会不知道有任何机器在整数内具有用户可访问的奇偶校验位。因此,委员会不知道有任何机器将奇偶校验位视为填充位。
编辑 2010 年 12 月 28 日下午 3 点 EST:我在几个月前发现了一个关于 comp.lang.c 的有趣讨论。
- Bitwise Operator Effects on Padding Bits (VelocityReviews reader)
- Bitwise Operator Effects on Padding Bits (Google Groups alternate link)
Dietmar 提出的一点我觉得很有趣:
请注意,填充位对于陷阱表示的存在不是必需的;不代表对象类型值的值位组合也可以。
【问题讨论】:
-
最后的评论是错误的。通过简单的计数参数,填充位对于陷阱表示的存在是必要的。 C 只允许无符号值的纯二进制表示,并且只允许有符号值的 3 种可能的表示,当值适合时,所有这些都与表示中对应的无符号类型一致。
-
R,我对 Dietmar 的引用来自后面的讨论,当时提到如果不支持负零
-0,它可能是一个陷阱表示,并且按位补码运算符可能会导致这样的表示。我假设一个例子是~(int)0,其中有符号整数表示是一个的补码,并且可能会根据实现导致陷阱表示。 -
虽然我刚才想到,符号位在标准中与值位是分开提到的,因此 -0 也需要符号位
-
@AQG:我同意你的 cmets。在非二进制补码实现中,只有一种可能的陷阱表示不依赖于填充位。
标签: c bit-manipulation padding bitwise-operators