C语言无符号整数右移问题:~0直接右移时空位未补0?
这个问题的核心其实是C语言中整数类型的默认规则和有符号/无符号右移行为的区别,咱们一步步拆解:
1. 先搞懂~0到底是什么
在C里,0默认是int类型(有符号整数)。~是按位取反操作,对int的每一位取反后,得到的是全1的有符号整数——也就是补码表示的-1(因为int的最高位是符号位,全1的补码对应十进制-1)。
当你用%u(无符号格式符)打印它时,C会把这个有符号的-1转换成无符号整数,结果就是unsigned int的最大值4294967295,但注意:此时~0本身的类型还是int,只是打印时被转换了。
2. 直接对~0右移为什么结果不变?
因为~0是int类型(有符号),C语言对有符号整数的右移采用算术右移:右侧丢弃低位,左侧填充符号位(也就是最高位的值,这里是1)。
所以~0 >> 2其实是对有符号的-1做算术右移2位,结果还是全1的int(也就是-1),用%u打印出来自然还是4294967295,看起来和原数一样。
3. 存入unsigned int变量后右移正常的原因
当你把~0(int类型的-1)赋值给unsigned int temp时,触发了类型转换:有符号整数-1会被转换成无符号整数,规则是加上2^N(N是无符号类型的位数,这里32位就是2^32),结果就是4294967295,此时temp的类型是无符号整数。
无符号整数的右移是逻辑右移:右侧丢弃低位,左侧填充0。所以temp >> 2就是把全1的无符号数右移2位,高位补0,结果就是1073741823,这和你预期的一致。
4. 左移为什么两种方式都正常?
不管是有符号还是无符号整数的左移,规则都是统一的:左侧丢弃高位,右侧填充0。所以不管是直接对~0(int的-1)左移,还是存入无符号变量后左移,结果都是把全1的二进制左移2位(丢弃最高两位,右侧补0),转换成无符号打印时结果一致,所以看起来都正常。
验证小技巧
如果想直接对~0做右移得到预期结果,你可以强制转换类型,比如:
printf("%u \n", (unsigned int)~0 >> 2);
这样就会先把~0转换成无符号整数,再做逻辑右移,结果就是1073741823。
内容的提问来源于stack exchange,提问作者Doreas




