无符号整数中的填充位和C89中的按位运算

时间:2010-12-17 23:05:01

标签: c bit-manipulation padding bitwise-operators

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

我希望让我的代码更具可移植性,我专注于确保我C89 compliant(在这种情况下)。我遇到的一个问题是填充整数。以这个极端的例子为例,取自GMP manual

  

然而,在Cray矢量系统上,可以注意到short和int总是存储在8个字节中(并且sizeof表示)但仅使用32或46位。指甲功能可以通过传递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;
}
  • 使用填充位XOR两个整数是否安全?
  • 不管填充位是什么,我不会XOR吗?

我无法在C89中找到此行为。

此外,c变量保证为0x3FFFFFFF,或者例如,如果两个填充位在a或b中都打开,c0xFFFFFFFF吗?

de相同的问题。我是通过移动来操纵填充位吗? 我希望在下面看到这一点,假设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 short的符号位。然后,作为32位有符号整数,在确定32位有符号int的值时会忽略一个填充位(在32位的中间)。但是,如果将此32位项目视为32位无符号整数,则该填充位对用户程序可见。 C委员会被告知有一台机器以这种方式工作,这就是填充位被添加到C99的一个原因。

     

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


编辑12/28/2010美国东部时间下午3点:几个月前我在comp.lang.c上发现了一个有趣的讨论。

Dietmar提出的一点我感兴趣:

  

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

1 个答案:

答案 0 :(得分:10)

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

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

修改

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

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

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