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

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

我期望让我的代码更具可移植性,我专注于确保我符合C89(在这种情况下)。 我遇到的问题之一是可能的填充整数。 以GMP手册中的这个极端例子为例:

然而,在Cray矢量系统中,可能会注意到short和int总是以8个字节存储(并且sizeof指示),但只使用32或46位。 指甲特征可以解释这一点,例如通过传递8 * sizeof(int)-INT_BIT。

我还在其他地方了解了这种填充类型。 实际上我昨天晚上读到了一篇关于SO的文章(原谅我,我没有链接,我会引用类似于内存的东西),如果你有一个双倍的60个可用位,其他4个可以用于填充,这些填充位可以用于某些内部目的,因此它们不能被修改。


举例来说,我的代码是在一个平台上编译的,其中一个无符号整数类型的大小为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: %Xnb: %Xnc: %Xnd: %Xne: %Xn", a, b, c, d, e );
    return 0;
}

用填充位异或两个整数是否安全?
我不会XOR无论填充位是什么?
我无法在C89中找到这种行为。
此外,c var保证为0x3FFFFFFF,或者如果例如两个填充位都在a或b上,则c将为0xFFFFFFFF?
与d和e相同的问题。 我是通过移动操纵填充位吗? 我期望在下面看到这一点,假设32位用于填充的2个最重要的位,但我想知道是否有这样的保证:

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

填充位总是最重要的位,或者它们可能是最不重要的位?

多谢你们


编辑12/19/2010美国东部时间下午5点 :克里斯托弗回答了我的问题。 谢谢!
我还问过(上面)填充位是否总是最重要的位。 这在C99标准的基本原理中被引用,答案是否定的。 我玩起来很安全,并且假设C89一样。 具体来说,C99的基本原理对于第6.2.6.2节(整数类型的表示)如此说明:

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

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


编辑12/28/2010美国东部时间下午3点 :我几个月前在comp.lang.c上发现了一个有趣的讨论。
按位运算符对填充位的影响(VelocityReviews reader)
按位运算符对填充位的影响(Google Groups alternate link)
Dietmar提出的一点我觉得很有趣:

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


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

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

编辑:

C90根本没有提到整数填充,但据我所知,'不可见的'前面或后面的整数填充位不应该违反标准(我没有通过所有相关章节来确保这是真的,虽然); 在C99的基本原理中提到,probaby是混合填充和值位的问题,否则标准将不需要改变。

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

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

链接地址: http://www.djcxy.com/p/36391.html

上一篇: C question: Padding bits in unsigned integers and bitwise operations (C89)

下一篇: How to shift bits across array of ints