【C语言】位运算

文章目录

前言:

C语言的位运算有6种:按位与&按位或|按位取反~按位异或^按位左移<<按位右移>>

注意:能够参与位运算的操作数必须是整型,以补码形式进行按位运算


(一)按位与& (双目运算符)

0 | 1 ⇒ 0
1 | 0 ⇒ 0
1 | 1 ⇒ 1
0 | 0 ⇒ 0

(1)迅速清零

#include <stdio.h>

int main()
{
	int a = 15;
	a = a & 0;
	printf("a = %d\n", a);
	return 0;
}

【C语言】位运算
结果:
【C语言】位运算

从这还不足以看出按位与&的真正魅力,主要做作用就在下面

(2)保留指定位

#include <stdio.h>

int main()
{
	int a = 15;
	a = a & 6;
	printf("a = %d\n", a);
	return 0;
}

【C语言】位运算
【C语言】位运算

(3)判断奇偶性

补码的最低位是0,就是偶数,1是奇数

所以使用任意数和1进行按位与,即(num & 1) == 0 ? 偶数 : 奇数

注意:逻辑运算符的优先级高是7,按位运算符的优先级低是9

我们来输出下[1 - 100] 之间的偶数

#include <stdio.h>
int main()
{
	for (int i = 1; i <= 100; i++)
	{
		if ((i & 1) == 0)
		{
			printf("%-4d", i);
		}
	}
	return 0;
}

【C语言】位运算

拓展:
按位与&不光能判断奇偶性,而且还能判断能够被2^n (n>=0)整除的数
总结:

  • 判断一个数num能否被2^n整除,使用(num & (2^n - 1))) == 0 ? 偶数 : 奇数
  • 例如:一个整数内否被4整除
#include <stdio.h>
int main()
{
   for (int i = 1; i <= 100; i++)
   {
   	if ((i & 3) == 0)
   	{
   		printf("%-4d", i);
   	}
   }
   return 0;
}

【C语言】位运算

(二)按位或 | (双目运算符)

0 | 1 ⇒ 1
1 | 0 ⇒ 1
1 | 1 ⇒ 1
0 | 0 ⇒ 0

(1)修改数据的指定位的值

例:把char类型的十进制100的第4个二进制位改成1
把100 : 1100 0100
使用 | : 0000 1000
结果: 1100 1100(108)

#include <stdio.h>

int main()
{
	char a = 100;
	a = a | 0x08;
	return 0;
}

【C语言】位运算

(三)按位取反~(单目运算符)

~0 ⇒ 1
~1 ⇒ 0

(1)方便表示一个数字,通常和& | 结合使用

#include <stdio.h>

int main()
{
	int a = 0x12345678;
	//  0001 0010 0011 0100 0101 0110 0111 1000
	//& 1111 1111 1111 1111 1111 1111 0000 0000
	//将a的后2位78变成00
	// 0001 0010 0011 0100 0101 0110 0000 0000
	int b = a & 0xffffff00;
	printf("b = %x\n", b);
	//第二种表示:1111 1111 1111 1111 1111 1111 0000 0000
	//~ 0000 0000 0000 0000 0000 0000 1111 1111
	//~255
	b = a & ~255;
	printf("b = %x\n", b);
	return 0;
}

【C语言】位运算

(四)按位异或^(双目运算符)

0 ^ 0 ⇒ 0
0 ^ 1 ⇒ 1
1 ^ 0 ⇒ 1
1 ^ 1 ⇒ 0

(1)按位异或的规律

  1. 结合律:a ^ (b ^ c) == (a ^ b)^ c
  2. 交换律:a ^ b == b ^ a
  3. 归零律:a ^ a == 0
  4. 恒等率:a ^ 0 == a
  5. 自反性:a ^ b ^ a == b

(2)判断两个数是否相等

//a == b;
//(a - b) == 0;
//(a ^ b) == 0;

(3)交换两个数

#include <stdio.h>
int main()
{
	int a = 10;
	int b = 20;
	
	a = a ^ b;	
	b = a ^ b;	// a ^ b ^ b == a
	a = a ^ b;	// a ^ b ^ a == b
	
	printf("a = %d, b = %d\n", a ,b);
	return 0;
}

【C语言】位运算

(4)一个整型数组里的value只出现了一次,其余数据都是两次,请找到这个数

int main()
{
	int arr[] = {2, 1, 5, 4, 2, 1, 6, 5, 6};
	int len = sizeof(arr) / sizeof(arr[0]);
	int ret = 0;
	for (int i = 0; i < len; i++)
	{
		ret = ret ^ arr[i];
	}

	printf("%d\n", ret);
	return 0;
}

【C语言】位运算

(四)按位左移<<,按位右移>>

<<左移:最低位填充0

>>右移:

  • 有符号数最高位填充符号位
  • 无符号数最高位填充0

练习题:计算一个整型数对应的二进制数中1的个数

(1)解法一
#include <stdio.h>
//得到一个整数二进制中的1的个数
int GetOneNum(int num)
{
	//计算二进制位个数
	int bit_num = sizeof(num) * 8;
	int count = 0;	//计数

	while (bit_num--)
	{
		if ((num & 1) == 1)
		{
			count++;
		}
		num >>= 1;
	}
	return count;
}

int main()
{
	int test = 0xd2;	//1101 0010
	printf("number of 1 : %d\n", GetOneNum(test));
	return 0;
}
(2)解法二
int GetOneNum(unsigned int num)
{
	int count = 0;	//计数

	while (num != 0)
	{
		if ((num & 1) == 1)
		{
			count++;
		}
		num >>= 1;
	}
	return count;
}
(3)解法三
int GetOneNum(int num)
{
	int count = 0;	//计数

	while (num != 0)
	{
		num = num & (num - 1);
		count++;
	}
	return count;
}
(4)解法四:查表法
/*
* 我们将四个位作为一个位移动的基本单元
* 得到每个单元的所有可能,然后四位四位的与运算
*/
int GetOneNum(int num)
{
	int num_4bit = sizeof(num) * 2;	//一字节 == 2个十六进制位
	int count = 0;	 
	//四位一个单元的所有可能     //计数
	//0000                      0
	//0001                      1
	//0010                      1
	//0011                      2
	//0100						1
	//0101						2
	//0110						2
	//0111						3
	//1000						1
	//1001						2
	//1010						2
	//1011						3
	//1100						2
	//1101						3
	//1110                      3
	//1111						4
	while (num_4bit--)
	{
		count = count + "0112122312232334"[num & 0x0f] - '0';
		num >>= 4;
	}
	return count;
}
上一篇:一文讲清楚补码的本质


下一篇:java leetcode之[动态规划 简单]191. 位1的个数