文章目录
前言:
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;
}
结果:
从这还不足以看出按位与&的真正魅力,主要做作用就在下面
(2)保留指定位
#include <stdio.h>
int main()
{
int a = 15;
a = a & 6;
printf("a = %d\n", a);
return 0;
}
(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;
}
拓展:
按位与&不光能判断奇偶性,而且还能判断能够被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;
}
(二)按位或 | (双目运算符)
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;
}
(三)按位取反~(单目运算符)
~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;
}
(四)按位异或^(双目运算符)
0 ^ 0 ⇒ 0
0 ^ 1 ⇒ 1
1 ^ 0 ⇒ 1
1 ^ 1 ⇒ 0
(1)按位异或的规律
- 结合律:a ^ (b ^ c) == (a ^ b)^ c
- 交换律:a ^ b == b ^ a
- 归零律:a ^ a == 0
- 恒等率:a ^ 0 == a
- 自反性: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;
}
(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;
}
(四)按位左移<<,按位右移>>
<<左移:最低位填充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;
}