今天主要学习一下位操作符。
今天也要心情愉悦的学习呀!
& 按位与:逐比特位运算 同1为1,其他为0
| 按位或 : 逐比特位运算 同0为0,其他为1
^ 按位异或 :逐比特位运算 相异为1,相同为0
~ 取反 :逐比特位运算 按位取反(单目操作符)
<< 左移 :逐比特位左移最低位补0
>>右移:逐比特位右移有符号补最高位补符号位,无符号数补0。
除了~取反,其他都是双目操作符。
答案是只适用于整形家族,不适合浮点型家族。
本质原因是因为两者的数据存储类型不同。
整形家族的存储在上篇说过了,不在赘述。
int a = 0;
scanf("%d", &a);
int count = 0;
while (a)
{
a = a&(a - 1);//每次把最低位丢弃,直到a为0.
count++;
}
printf("%d\n", count);
int a = 0;
int count = 0;
scanf("%d", &a);
while (a+1)
{
a = a | (a + 1);
count++;
}
printf("%d\n", count);
这个代码很有趣,是采用数据溢出后截断来使判断条件成立的。
首先,判断处采用a+1是因为要使0也要进去,更巧的是,当a+1等于0的时候,刚好a是 -1,我们知道-1的二进制补码中是没有0的,所以刚好符合,这是采用的每次使一个比特位的变成1,到最后使数据变为负数(-1),再加1变为0,终止循环。
首先要知道一些最基本的结论:
1 .一个数异或0,还是它本身。
2.一个数异或它本身为0
这是根据异或概念得出的。
下面再看这题,是不是有点思路了。
先a异或b,然后再进行一次异或,相当于b = b^ b^a.
同理可得出a。
int a = 10;
int b = 20;
printf("before:%d %d\n", a, b);
a = a^b;
b = a^b;
a = a^b;
printf("after:%d %d\n", a, b);
下面是数学法。
int a = 10;
int b = 20;
printf("before:%d %d\n", a, b);
a = a + b;
b = a - b;
a = a - b;
printf("after:%d %d\n", a, b);
异或法比数学法最大的好处就是不用考虑溢出的问题,如果两个非常大的数进行数学法运算可能会溢出。
左移比较简单,丢弃高位,低位补0。
右移分情况讨论了 :
算数右移 :有符号的数来说,最高位补符号位。
逻辑右移:无符号的数来说,最高位补0。
看个例子 :
int a = -1;
unsigned int b = -1;
printf("%d\n", a >> 1);
printf("%u\n", b >> 1);
运行后发现,先打印的是-1,然后是打印的是230-1.
先分析a>>1,因为a是有符号的负数,所以补位时最高位符号位1,最后的补码值还是全1.
再看b>>1,因为b是无符号数,所以补位时最高位补0,最后是出来第一个比特位是0,其他都为1。
那么移位的范围是什么呢?
首先int型的数据只有32位,所以移位最大是31位,那么最小值呢?是最小值是**-31位吗?**不是的,左移还有右移都不能移位负数位。
所以移位的范围是0~31位。
看个例子
比较下优先级的问题。
int a = 1;
a = a << 2 + 3;
printf("%d", a);
首先,结果是32,那么这样看的话,是先进行(2+3),在进行移位。
所以使用移位符时,要考略优先级的问题。
使用移位符可以逐比特位置为0或1.
逐比特位,置1.
unsigned int a = 1;
int i = 0;
for (i = 0; i < 32; i++)
{
a = a|(a << i);
}
printf("%d", a);
因为最后是有符号数,所以打印为-1。
逐比特位,置0
unsigned int a = -1;
for (int i = 0; i < 32; i++)
{
a = a & (a >> i);
}
printf("%d", a);
因为a为无符号数,所以补位时,补0,进行移位后在进行按位或。最后打印是0。