一.移位操作符 移动的是二进制位 操作数只能是整数
(1)<<左移 左边抛弃 右边补0
(2)>>右移 逻辑右移/算术右移 取决于编译器的实现,常见的编译器都是算术右移
逻辑右移 :左边补0 右边丢弃
算术右移 :左边用原符号位填充,右边丢弃
对于移位操作符,不要移动负数位,这个是标准未定义的。
代码示例:
#include<stdio.h>
int main()
{
int a = 6;
int b = (a << 1);
//00000000000000000000000000000110
//00000000000000000000000000001100
printf("%d\n", b);//12
printf("%d\n", a);//6
return 0;
}
对于负数:
#include<stdio.h>
int main()
{
int a = -6;
int b = (a << 1);
//10000000000000000000000000000110
//11111111111111111111111111111001
//11111111111111111111111111111010 -6补码
//11111111111111111111111111110100 b中得到的补码
// 再次转换
//10000000000000000000000000001011
//10000000000000000000000000001100 -12
//1111111111111111111111111111
printf("%d\n", b);//-12
printf("%d\n", a);//-6
return 0;
}
#include<stdio.h>
int main()
{
int num = 10;
int n = num >> 1;
printf("%d\n", n);
printf("%d\n", num);
return 0;
}
复合运算
#include<stdio.h>
int main()
{
int num = -1;
num = num >> 1;
num >= 1;//复合
return 0;
}
二.位操作符
操作数必须是整数 操作的是二进制位
& 按位与 只要有0则为0 同时为1才为1
| 按位或 只要有1则为1 两个为0才为0
^ 按位异或 相同为0 相异为1
~ 按位取反
1.按位与 &
#include<stdio.h>
int main()
{
int a = 3;
int b = -5;
int c = a & b;
//00000000000000000000000000000011 3的补码
//10000000000000000000000000000101
//11111111111111111111111111111010
//11111111111111111111111111111011 -5的补码
//00000000000000000000000000000011
//11111111111111111111111111111011
// &
//00000000000000000000000000000011 -补码
printf("%d", c);//3
return 0;
}
2.按位或 |
#include<stdio.h>
int main()
{
int a = 3;
int b = -5;
int c = a | b;
//00000000000000000000000000000011 3的补码
//10000000000000000000000000000101
//11111111111111111111111111111010
//11111111111111111111111111111011 -5的补码
//00000000000000000000000000000011
//11111111111111111111111111111011
// |
//11111111111111111111111111111011 ---补码
//10000000000000000000000000000100
//10000000000000000000000000000101 --原码
printf("%d", c);//-5
return 0;
}
3.按位异或 ^
#include<stdio.h>
int main()
{
int a = 3;
int b = -5;
int c = a ^ b;
//00000000000000000000000000000011 3的补码
//10000000000000000000000000000101
//11111111111111111111111111111010
//11111111111111111111111111111011 -5的补码
//00000000000000000000000000000011
//11111111111111111111111111111011
//^
//11111111111111111111111111111100
//10000000000000000000000000000011
//10000000000000000000000000000100
printf("%d", c);//-8
return 0;
}
题目拓展:不创建临时变量,实现两个整数的交换。
//a^a=0;
//0^a=a;
#include <stdio.h>
int main()
{
int a = 3;
int b = 5;
printf("交换前:a=%d b=%d\n", a, b);
a = a ^ b;
b = a ^ b;//a^b^b--->0---->a 等价于b=a
a = a ^ b;//a^b^a--->0----->b 等价于a=b
printf("交换后:a=%d b=%d\n", a, b);
return 0;
}
//异或运算不会溢出
按位取反 ~
#include<stdio.h>
int main()
{
int a = 0;
int b = ~a;
//00000000000000000000000000000000
//11111111111111111111111111111111
//10000000000000000000000000000000
//10000000000000000000000000000001
printf("%d\n", b);//-1
return 0;
}
代码练习1:求一个整数在内存中二进制中1的个数
方法1:
//针对负数有问题
#include<stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
int count = 0;
while (n)
{
if (n % 2 == 0)
count++;
n /= 2;
}
printf("%d", count);
return 0;
}
方法2:
//进阶
#include<stdio.h>
int main()
{
unsigned int n = 0;
scanf("%d", &n);
int count = 0;
while (n)
{
if (n % 2 == 1)
count++;
n /= 2;
}
printf("%d\n", count);
return 0;
}
方法3:
//按位与 移位的方法
#include<stdio.h>
int main()
{
int n = 0;
int count = 0;
scanf("%d", &n);
int i = 0;
for (i = 0; i < 32; i++)
{
if (((n >> i) & 1) == 1)
count++;
}
printf("%d", count);
}
方法4:
//n=n&(n-1)这个表达式能将n的二进制中最右边的1去掉
#include<stdio.h>
int main()
{
int n = 0;
int count = 0;
scanf("%d", &n);
while (n)
{
n = n & (n - 1);
count++;
}
printf("%d\n", count);
return 0;
}
代码练习2:
如何判断一个数是否是2的次方数:2的n次方二进制中只有一个1
//00000010//2
//00000100//4
//00000101//5
//00001000//8
//00001001//9
#include<stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
if ((n & (n - 1)) == 0)
{
printf("%d是2的次方数\n", n);
}
else
{
printf("%d不是2的次方数\n", n);
}
return 0;
}
代码练习3: 将13二进制序列的第五位修改为1,然后再改回0。
#include <stdio.h>
int main()
{
int n = 13;
//把第五位改成1
n |= (1 << 4);
printf("%d\n", n);
//改成0
n &= (~(1 << 4));
printf("%d\n", n);
return 0;
}