右移 C 中的无符号整数问题:移位 ~0 时腾出位不为 0



据我了解,当在 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 都完全没问题。我不确定这里发生了什么。

表达式

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

当你用%u打印它时,printf函数读取这个值-1的有符号int作为unsigned int,并打印0xffffffffunsigned int的意义。

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

~0U >> 2

这将确保它是未签名的。否则,您已签署操作。

整数文本始终为 int 类型(有符号int(。现在,当您左移时,它是标志扩展的。

%u期望未签名的int。您已向其传递已签名的 int。这是未定义的行为。

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

#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 

最新更新