书里看到这样一个题目,让读者看看下面代码两次输出结果是否一致,为什么
int i = 0xcffffff3;
printf("%x\n", 0xcffffff3>>2);
printf("%x\n", i>>2);
输出结果
33fffffc
f3fffffc
下面列出分析思路。
- 移位结果计算
0xcffffff3: 1100 1111 1111 1111 1111 1111 1111 0011
右移两位后: 11 0011 1111 1111 1111 1111 1111 1100
对应十六进制结果:
33fffffc - 那么f3fffffc是怎么来的呢?
0xcffffff3:1100 1111 1111 1111 1111 1111 1111 0011
0xf3fffffc:1111 0011 1111 1111 1111 1111 1111 1100
对比0xcffffff3的二进制明显是右移时补位填1了 - 打印二者类型
将代码改为如下,执行
int i = 0xcffffff3;
printf("%x\n", 0xcffffff3>>2);
printf("%x\n", i>>2);
结果
root@lssd:~/lumut/test_all# gcc xm.c -o xm -g -Wall
xm.c:15:6: warning: return type of ‘main’ is not ‘int’ [-Wmain]
15 | void main()
| ^~~~
xm.c: In function ‘main’:
xm.c:24:14: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘unsigned int’ [-Wformat=]
24 | printf("%s\n", 0xcffffff3>>2);//33fffffc
| ~^ ~~~~~~~~~~~~~
| | |
| | unsigned int
| char *
| %d
xm.c:25:14: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
25 | printf("%s\n", i>>2);//f3fffffc
| ~^ ~~~~
| | |
| char * int
| %d
显然移位表达式是无符号型,变量i是int型。
C语言定义int类型时,默认是有符号型,所以这里变量i首位是1,被处理为负数,负数右移补位有可能补0也有可能补1,x86平台的gcc编译器,最高位是移入1的。
而表达式0xcffffff3>>2中0xcffffff3首位是1,编译器处理成无符号整型,因为c的二进制首位是1,如果是有符号数,则会处理成负数。
5.验证上述思路,修改代码增加二进制首位不为1的十六进制数进行移位,如下:
int i = 0xcffffff3;
printf("%x\n", 0xcffffff3>>2);
printf("%x\n", i>>2);
printf("%s",i);
printf("%s",0x0ffffff3);
结果
root@lssd:~/lumut/test_all# gcc xm.c -o xm -g
xm.c: In function ‘main’:
xm.c:26:14: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
26 | printf("%s",i);
| ~^ ~
| | |
| | int
| char *
| %d
xm.c:27:14: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
27 | printf("%s",0x0ffffff3);
| ~^ ~~~~~~~~~~
| | |
| | int
| char *
| %d
二者都是int型了。
5.总结
1.0x3ffffff3和0xcffffff3这两个常量虽然看起来差不多,但前者是int型,而后者是unsigned int型;
2.负数的移位运算应注意编译器运算的结果。
书籍:《Linux C编程一站式学习》 作者:宋劲杉