位运算符
C语言中,一共有6个位运算符,优先级由高到低分别是(其中<<
与>>
优先级相同)~
, <<
, >>
, &
, ^
, |
分别说明:
位运算符 | 作用 |
---|---|
~ | 按位取反,1变为0, 0变为1 |
<< | 左移,最高位舍,最低位补0,例: 0000 0000 0000 1001 左移1位, =>0000 0000 0001 0010 |
>> | 右移 , 最低位舍,最高位补0, 例:0000 0000 0000 1001 右移一位 =>0000 0000 0000 0100 , |
& | 按位与,只有当其同为1时,才为1,否则为0 |
^ | 按位异或,相同为0,不同为1。只有两个不同时,才为1,否则为0 |
| | 按位或,有1为1,没有为0,只要两者中存在一个1,就为1,两个都是1也为1,否则为0 |
注意: 1001>>1 并不等于100,这里的1001表示的是10进制数,想表示二进制数1001,需加上前缀0b,即0b1001。
- M<<N,表示将M左移N位,所得的数相当于,M乘以2的N次方
- 例: 要得到2的3次方, 1<<3效率最高,而不是2 * 2 * 2或者 pow(2,3)
- 类似的,M>>N,表示将M右移N位,所得的数相当于,M除以2的N次方,整数与整数相除结果也为整数,注意。
- 例: 9>>1 , 结果为9/2等于 4
- 如果整数a,b相等,可得到 a^b等于 0 . 即 if(a!=b)等价于if(a ^ b)
- 大小写转换: x^=32 , 如输入A(65),转换为a(97); 如输入z(122),转换为Z(90)
- 实例:将输入的字符串,大写转小写,小写转大写
int main(){
char str[10], *p;
p = str;
scanf("%s", p);
for (int i = 0; str[i] != '\0'; i++)
str[i] ^= 32;
printf("%s", p);
return 0;
}
负数的存储形式
按编译系统不同,整形在C中占用2字节或4字节, 一字节8位 .
以下讨论的按2字节举例: 只讨论整形 .
说负数的存储形式前,先说正数的存储形式 , 正数的存储形式,就是其二进制.
例:1 的存储形式,0000 0000 0000 0001
9的存储形式: 0000 0000 0000 1001
而 负数的存储形式是其绝对值的存储形式按位取反,再加一 .
此处按4字节算:
整数1的存储方式:
0000 0000,0000 0000,0000 0000,0000 0001
整数 -1 的存储方式:
0000 0000,0000 0000,0000 0000,0000 0001
按位取反:
1111 1111,1111 1111,1111 1111,1111 1110
再加上1:
1111 1111,1111 1111,1111 1111,1111 1111
所以整数 -1 的存储方式为:
1111 1111,1111 1111,1111 1111,1111 1111
案例
#include <stdio.h>
int main(){
int x = M;
printf("%d",~x);
return 0;
}
- M为一个整数常量 , 输出的值始终为 -(M+1),如当M为1时,输出打印 -2
- 为啥?
首先,就要说到C语言中,负数的存储形式:负数的存储形式是其绝对值的二进制形式 按位取反再加一
例: -1 (如整形按两个字节计算)
其绝对值 1 的二进制形式: 0000 0000 0000 0001
按位取反 ~: 1111 1111 1111 1110
再加一: 1111 1111 1111 1111
所以-1在内存中的存储形式为: 1111 1111 1111 1111
内存中,首位(最高位)为0,表示一个正数,为1表示一个负数。
所以,当遇到存储形式为:0000 0000 0000 0001 的, 首先看其最高位是0(是正数)还是1(还是负数)。
如是 0 :则直接按二进制转十进制, 0000 0000 0000 0001的十进制便是 1,所以其表示的也是1。
如存储形式为:1000 0000 0000 0001,最高位为1,便不可直接按二进制转十进制得到 32769,
因为最高位为1,代表负数,而负数的存储方式与正数不同,不可直接转化为十进制,需先减一,再按位取反,回推。
减一: 1000 0000 0000 0000
按位取反:0111 1111 1111 1111
再转十进制:32767
又因首位是1,表示负数,所以1000 0000 0000 0001所表示的数是 -32767,并不是-1,也不是32769。