右移在C中的无符号整数问题:当移位〜0时,空出的位不为0?

时间:2018-01-07 04:36:55

标签: c bit bit-shift kernighan-and-ritchie

据我所知,当将无符号整数右移到C中的多个位置时,左边的空位置用零填充。

然而,我一直试图右移〜0(这将是1111 ... 1111)而没有任何成功。试图将任意数量的位置右移它会产生相同的值,除非我在移位之前将整数存储在变量中:

#include <stdio.h>

int main() {

    // Using an expression:
    printf("%u \n", ~0);
    printf("%u \n", ~0 >> 2);
    unsigned int temp = ~0;
    // Using a variable to store the value before shift:
    printf("%u \n", temp);
    printf("%u \n", temp >> 2);

    return 0;

}

输出:

4294967295                                                                                   
4294967295                                                                               
4294967295                                                                                  
1073741823 

当以任一方式执行时,左移〜0完全正常。我不确定这里发生了什么。

3 个答案:

答案 0 :(得分:3)

~0U >> 2

这将确保它是未签名的。否则你就签了名。

积分文字始终为int类型(已签名int)。现在当你离开时,它会被标记延长。

%u期望unsigned int。您已将一个signed int传递给它。这是未定义的行为。

答案 1 :(得分:3)

表达式0的类型为int,而非unsigned int。因此,~0是值为int 0xffffffff (假设您看起来像32位int)。在大多数系统上,这意味着-1,右移有符号整数将进行符号扩展(如果它开始为负则保持为负),再次给予0xffffffff

当您使用%u进行打印时,printf函数会将带有int的已签名-1作为unsigned int读取,并打印{{1} }}表示0xffffffff

请注意,所有这些都是大多数时间在大多数系统上发生的情况。这有多个未定义或实现定义行为的实例(负unsigned int的位模式,右移负int s,以及int格式说明符通过时的含义在%u而不是int)。

答案 2 :(得分:0)

以下建议的代码更正OP代码并解决问题的注释,包括删除未定义的行为。

#include <stdio.h>

int main( void )
{
    // Using an expression:
    printf("%u \n", ~0U);
    printf("%u \n", ~0U >> 2);
    unsigned int temp = ~0U;
    // Using a variable to store the value before shift:
    printf("%u \n", temp);
    printf("%u \n", temp >> 2);

    return 0;
}

输出是:

4294967295 
1073741823 
4294967295 
1073741823