最近碰到了一个问题:
#include <cstdio>
int main(){
int x;
printf("%x\n",~x^x);
return 0;
}
这段代码输出是多少?
碰到这个问题的第一感觉,这难道不是乱码?
这个结果会是乱码吗?我们来复习一下相关知识
格式控制符 | 输出格式 |
---|---|
%d | 按十进制数据的实际长度输出 |
%ld | 输出长整型数据 |
%md | m为指定的输出字段的宽度,如果数据的位数小于m,则左端补空格,若大于m,则按实际位数输出 |
%u | 输出无符号整型 |
%c | 输出一个字符 |
%f | 用来输出实数,包括单精度和双精度以小数形式输出,不指定字符宽度,由系统自动指定,整数部分自动输出小数部分输出6位,超过6位的四舍五入 |
%.mf | 输出实数时小数点后保留m位 |
%o | 以八进制整数形式输出 |
%s | 用来输出字符串 |
%x(或 %X 或 %#x 或 %#X) | 以十六进制形式输出整数(x大写输出字母为大写x小写输出字母为小写) |
– | – |
按位取反
- ~表示按位取反。
- 我们来举一个例子:如果一个int类型的数2取反应该是多少呢?int类型在计算机中存储位数是32位,也就是说,2在计算机中应该是0000 0000 0000 0000 0000 0000 0000 0010,取反,得1111 1111 1111 1111 1111 1111 1111 1101,最高位是符号位,1表示负数。0表示正数,那这个数应该是一个负数,我们必须要求出它的源码。
- 对于一个负数,我们已知的是它的补码,求它的源码的方法是,先对补码取反,再加一,最后在外面加一个负号。
- 那上面这个问题补码应该是1111 1111 1111 1111 1111 1111 1111 1101,取反,得0000 0000 0000 0000 0000 0000 0000 0010,再加一,得 0000 0000 0000 0000 0000 0000 0000 0011,表示的数就是3,可以用下面的代码在计算机里运行一下。
#include <cstdio>
int main(){
int x;
printf("%d\n",~2);
return 0;
}
按位异或
- ^表示按位异或。
- 例如:计算a^b时,根据操作数a与b每位的值,计算结果,当a与b对应位上的值相同时,算出结果的相应位上为0,否则为1,当然这里面输入输出都是十进制,只有在计算机内部运行才是二进制数。
- 例:2^3,相当于二进制数10和11,运算时遵循同出0,异出1,得到的结果应该是01,转化成十进制就是1。
这样回过头来看最开始的问题。
优先级是按位取反大于按位异或
对于一个int类型的数x(32位),~x使得得到的二进制数相对于x每个都相反,这样再对它按位异或,同出0,异出1,所以得到的应该是1111 1111 1111 1111 1111 1111 1111 1111 如果转化成十进制,应该取反码,再加一,最后加负号,所以是-1;如果转化成16进制,每个1111都可以转化成f(16进制中f表示15),所以就应该是8个f。