C问题:无符号整数和按位运算中的填充位(C89)

我有很多代码对无符号整数执行按位运算。 我编写了我的代码,假设这些操作是在固定宽度的整数上,没有任何填充位。 例如,32位无符号整数的数组,其中所有32位可用于每个整数。

我希望使我的代码更具可移植性,并且我专注于确保我符合C89 (在这种情况下)。 我遇到的一个问题是填充整数。 拿这个极端的例子,取自GMP手册 :

然而,在Cray矢量系统上,可以注意到short和int总是以8个字节存储(并且sizeof指示),但仅使用32或46位。 指甲function可以通过传递例如8 * sizeof(int)-INT_BIT来解决这个问题。

我也在其他地方读过这种类型的填充物。 我昨晚真的在SO上看了一篇post(请原谅我,我没有链接,我要引用类似记忆的东西),如果你有一个带有60个可用位的双,另外4个可以用于填充和那些填充位可以用于某些内部目的,因此它们不能被修改。

例如,假设我的代码是在一个平台上编译的,其中unsigned int类型的大小为4个字节,每个字节为8位,但最重要的2位是填充位。 在这种情况下,UINT_MAX会是0x3FFFFFFF(1073741823)吗?

#include  #include  /* 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; /* ?? __000001111111111111111111111111 */ printf( "a: %X\nb: %X\nc: %X\nd: %X\ne: %X\n", a, b, c, d, e ); return 0; } 

使用填充位XOR两个整数是否安全?
不管填充位是什么我不会XOR?
我找不到C89中涵盖的这种行为。
此外,c var保证为0x3FFFFFFF,或者例如,如果两个填充位在a或b中都是on,那么c将是0xFFFFFFFF?
与d和e相同的问题。 我通过移动来操纵填充位吗? 我希望在下面看到这一点,假设32位,其中2个最高位用于填充,但我想知道这样的事情是否有保证:

 a: 2AAAAAAA b: 15555555 c: 3FFFFFFF d: 3FFFFFE0 e: 01FFFFFF 

填充位总是最高有效位还是最低有效位?

多谢你们

编辑12/19/2010美国东部时间下午5点 :Christoph回答了我的问题。 谢谢!
我还问过(上面)填充位是否始终是最重要的位。 这在C99标准的基本原理中被引用,答案是否定的。 我正在玩它安全并假设C89相同。 以下是C99基本原理对§6.2.6.2(整数类型表示)的说法:

填充位是用户可访问的无符号整数类型。 例如,假设一台机器使用一对16位短路(每个都有自己的符号位)来构成一个32位的int,并且当在这个32位int中使用时,忽略较低short的符号位。 然后,作为32位有符号整数,在确定32位有符号int的值时会忽略一个填充位(在32位的中间)。 但是,如果将此32位项目视为32位无符号整数,则该填充位对用户程序可见。 C委员会被告知有一台机器以这种方式工作,这就是填充位被添加到C99的一个原因。

脚注44和45提到奇偶校验位可能是填充位。 委员会不知道任何具有用户可访问的奇偶校验位的机器在整数内。 因此,委员会不知道任何将奇偶校验位视为填充位的机器。

编辑12/28/2010美国东部时间下午3点 :几个月前我在comp.lang.c上发现了一个有趣的讨论。
填充位上的按位运算符效果(VelocityReviews阅读器)
填充位的按位运算符效果(Google网上论坛备用链接)
Dietmar提出的一点我感兴趣:

让我们注意,填充位不是存在陷阱表示所必需的; 不表示对象类型值的值位组合也可以。

按位运算(如算术运算)对值进行操作并忽略填充。 实现可能会也可能不会修改填充位(或在内部使用它们,例如作为奇偶校验位),但便携式C代码将永远无法检测到这一点。 任何值(包括UINT_MAX )都不包括填充。

如果您使用sizeof (int) * CHAR_BIT ,然后尝试使用shift来访问所有这些位,那么整数填充可能会导致问题。 如果你想要是可移植的,要么只使用( unsignedchar ,固定大小的整数(添加C99),要么以编程方式确定值位数。 这可以在编译时使用预处理器通过比较UINT_MAX与2的幂或在运行时通过使用位操作来完成。

编辑:

C90根本没有提到整数填充,但据我所知,“隐形”前置或尾随整数填充位不应违反标准(我没有通过所有相关部分来确保实际情况如此)虽然); 如在C99原理中提到的,混合填充和值位有问题,否则,标准就不需要改变了。

至于用户可访问的含义:填充位是可访问的,只要你可以通过使用((unsigned char *)&foo)[…]上的位操作来获取foo (包括填充)的任何位。 但是在修改填充位时要小心:结果不会改变整数的值,但可能会创建陷阱表示。 在C90的情况下,这是隐式未指定的(如未提及的那样),在C99的情况下,它是实现定义的。

然而,这不是基本原理引用的内容:引用的体系结构通过两个16位整数表示32位整数。 在无符号类型的情况下,结果整数具有32个值位并且精度为32; 在有符号整数的情况下,它只有31个值位且精度为30:16位整数的符号位之一用作32位整数的符号位,另一个被忽略,从而创建由值位包围的填充位。 现在,如果您将32位有符号整数作为无符号整数(明确允许并且不违反C99别名规则)访问,则填充位将成为(用户可访问的)值位。