无符号整数的填充位与C89中的按位操作

hfyxw5xn  于 2023-08-03  发布在  其他
关注(0)|答案(1)|浏览(131)

我有很多对无符号整数执行按位操作的代码。我在编写代码时假设这些操作是对固定宽度的整数进行的,没有任何填充位。例如,一个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会是0x 3FFFFFFF(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
de也是如此。我是否通过移位操作填充位?我希望在下面看到这一点,假设32位,其中2个最高有效位用于填充,但我想知道这样的事情是否得到保证:

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


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

EDIT 12/19/2010 5PM EST:Christoph回答了我的问题。谢谢你,谢谢

我还问过(上面)填充位是否总是最重要的位。这在C99标准的基本原理中被引用,答案是否定的。我是在玩安全游戏,并假设C89也是如此。下面是C99基本原理对§6.2.6.2(整数类型的表示)的具体说明:
填充位在无符号整数类型中是用户可访问的。例如,假设一台机器使用一对16位的短整型(每个短整型都有自己的符号位)来组成一个32位的整型,当在这个32位的整型中使用时,下面的短整型的符号位被忽略。然后,作为32位有符号整数,有一个填充位(在32位的中间),在确定32位有符号整数的值时忽略该填充位。但是,如果这个32位项被视为32位无符号整型,那么该填充位对用户程序是可见的。C委员会被告知,有一台机器是这样工作的,这就是C99添加填充位的原因之一。
脚注44和45提到奇偶校验位可以是填充位。委员会不知道任何机器的用户可访问的奇偶校验位在一个整数。因此,委员会不知道有任何机器将奇偶校验位视为填充位。

EDIT 12/28/2010 3PM EST:几个月前我在comp.lang.c上发现了一个有趣的讨论。

Dietmar提出的一个观点我觉得很有趣:
让我们注意到填充位对于陷阱表示的存在不是必需的;不表示对象类型的值的值位的组合也可以。

jq6vz3qz

jq6vz3qz1#

按位操作(如算术操作)对值进行操作并忽略填充。该实现可能会也可能不会修改填充位(或在内部使用它们,例如作为奇偶校验位),但可移植C代码将永远无法检测到这一点。任何值(包括UINT_MAX)都不包含填充。
整数填充可能会导致问题的地方是,如果你使用像sizeof (int) * CHAR_BIT这样的东西,然后尝试使用移位来访问所有这些位。如果你想移植,要么只使用(unsignedchar,固定大小的整数(C99加法),要么通过编程确定值位的数量。这可以在编译时用预处理器通过比较UINT_MAX和2的幂来完成,或者在运行时通过使用位操作来完成。

编辑:

C90完全没有提到整数填充,但据我所知,“不可见”的前后整数填充位不应该违反标准(尽管我没有阅读所有相关章节以确保情况确实如此);可能存在如C99原理中所提及的混合填充位和值位的问题,因为否则不需要改变标准。
关于用户可访问的含义:填充位是可访问的,因为您总是可以通过在((unsigned char *)&foo)[…]上使用位操作获得foo的任何位(包括填充)。但是,在修改填充位时要小心:结果不会改变整数的值,但可能会创建一个陷阱表示。在C90的情况下,这是隐式未指定的(因为根本没有提到),在C99的情况下,它是实现定义的。
但这并不是他引用的理由:所引用的体系结构通过两个16位整数来表示32位整数。在无符号类型的情况下,结果整数具有32个值位和32的精度;在有符号整数的情况下,它只有31个值位和30的精度:16位整数的符号位之一被用作32位整数的符号位,另一个被忽略,从而创建由值位包围的填充位。现在,如果您将32位有符号整数作为无符号整数访问(这是明确允许的,并且不违反C99别名规则),则填充位将成为(用户可访问的)值位。

相关问题