位操作符详解,和一些位运算小技巧

今天主要学习一下位操作符。

位操作符详解,和一些位运算小技巧_第1张图片

今天也要心情愉悦的学习呀!

1.都有哪些操作符?怎么用呢?

& 按位与:逐比特位运算 同1为1,其他为0
| 按位或 : 逐比特位运算 同0为0,其他为1
^ 按位异或 :逐比特位运算 相异为1,相同为0
~ 取反 :逐比特位运算 按位取反(单目操作符)
<< 左移 :逐比特位左移最低位补0
>>右移:逐比特位右移有符号补最高位补符号位,无符号数补0
除了~取反,其他都是双目操作符。

2.位操作符适用于哪些数据类型呢?

答案是只适用于整形家族,不适合浮点型家族。
本质原因是因为两者的数据存储类型不同。
整形家族的存储在上篇说过了,不在赘述。

  • 整形家族存储方式
    浮点型家族的存储方式,要符合IE754的规定。

3.按位与 按位或 按位异或 的实例

例 1: 求二进制中1的个数。 采用&(按位与)

    int a = 0;
	scanf("%d", &a);
	int count = 0;
	while (a)
	{
		a = a&(a - 1);//每次把最低位丢弃,直到a为0.
		count++;
	}
	printf("%d\n", count);

例 2:求二进制中0的个数 采用 | (按位或),(很有趣,可以看看)

	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,终止循环。

例 3: 采用 ^ (按位异或)交换两个变量的值。

首先要知道一些最基本的结论:
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);

异或法比数学法最大的好处就是不用考虑溢出的问题,如果两个非常大的数进行数学法运算可能会溢出。

4.左移 右移操作符

左移比较简单,丢弃高位,低位补0。
右移分情况讨论了 :
算数右移 :有符号的数来说,最高位补符号位。
逻辑右移:无符号的数来说,最高位补0。

看个例子 :

    int a = -1;
	unsigned int b = -1;
	printf("%d\n", a >> 1);
	printf("%u\n", b >> 1);

位操作符详解,和一些位运算小技巧_第2张图片
运行后发现,先打印的是-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),在进行移位。
所以使用移位符时,要考略优先级的问题。

5.移位符应用

使用移位符可以逐比特位置为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。

6. 一些技巧

  1. x&1 == 0判断是否偶数,偶数的最后一位比特位都是0.
  2. 两个数的值可以通过异或交换。
  3. x & (x-1)可以使最右边的比特位上的1变为0.
  4. 对于正数而言,x&(x-1)== 0就是判断是不是2的幂次方。
  5. 两个相同的数异或,结果是0,一个数和0异或,结果是他本身。 可以用来找数。

7.下期预告

这期还是没把 ++的东西写完。下期一定讲++和–相关的知识。
下期更精彩~~~
位操作符详解,和一些位运算小技巧_第3张图片

你可能感兴趣的