(与进制有关的操作符)

1.原码，反码，补码

• 按照一个数的正负，直接写出它的二进制表示形式就是原码
• 正数的原码、反码、补码是相同的
• 负数的原码、反码、补码要经过计算的
• 反码：原码的符号位不变，其他位按位取反
• 补码：反码+1
• 内存中存储的形式是：补码的二进制，所以在参与移位时，移动后都是补码

`int n = 10`，整形占四个字节（32bit） 00000000000000000000000000001010 原码 00000000000000000000000000001010 反码 00000000000000000000000000001010 补码 `int n = -10` 10000000000000000000000000001010 原码 111111111111111111111111111111110101 反码 111111111111111111111111111111110110 补码

2.移位操作符

左移操作符 <<

``````int main()
{
//对正数的左移
int a = 10;

int b = a << 1;
printf("%d\n", a);
printf("%d\n", b);
}
``````

00000000000000000000000000001010 -10的补码，进行左移 左移后的补码：00000000000000000000000000010100 输出结果：

``````int main()
{
//对负数的左移
int a = -10;
int b = a << 1;
printf("%d\n", a);
printf("%d\n", b);
}
``````

a的补码：111111111111111111111111111111110110
111111111111111111111111111111101100 -b的补码 10000000000000000000000000010100 -b的原码 输出结果：

右移操作符 >>

``````int num = 10;
num>>-1;//error
``````

3.位操作符

& -按位与 | -按位或 ^ -按位异或

按位与&

``````int main()
{
int a = 3;
//00000000000000000000000000000011 a的补码
int b = -5;
//10000000000000000000000000000101
//11111111111111111111111111111010
//11111111111111111111111111111011  b的补码
int c = a&b;
//00000000000000000000000000000011 a的补码
//11111111111111111111111111111011  b的补码
//00000000000000000000000000000011  c的补码
}
``````

按位或 |

``````int main()
{
int a = 3;
//00000000000000000000000000000011 a的补码
int b = -5;
//10000000000000000000000000000101
//11111111111111111111111111111010
//11111111111111111111111111111011  b的补码
int c = a|b;
//00000000000000000000000000000011 a的补码
//11111111111111111111111111111011  b的补码
//11111111111111111111111111111011  c的补码
}
``````

按位异或 ^

``````int main()
{
int a = 3;
//00000000000000000000000000000011 a的补码
int b = -5;
//10000000000000000000000000000101
//11111111111111111111111111111010
//11111111111111111111111111111011  b的补码
int c = a^b;
//00000000000000000000000000000011 a的补码
//11111111111111111111111111111011  b的补码
//11111111111111111111111111111000  c的补码
}
``````

1.a^a = 0 2.0^a = a 3.异或支持交换律

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

4.几道例题

1.求一个数的二进制形式中有多少个1

• 使用前面的取模除法运算：
``````//二进制中1的个数
int NumberOf1(int n)
{
int count = 0;
while (n)
{

if (n % 2 == 1)   //如果最后一位为1.count+1
{
count++;
}
n = n / 2;
}
return count;
}
``````

• 使用`&`,`>>`
``````int NumberOf1(int n)
{
int count = 0;
while (n>0)
{
int a = n & 1;
if (a==1)
{
count++;
}
n = n >> 1;
return count；
}
``````

``````int NumberOf1(int n)
{
int i = 0;
int count = 0;
for (i = 0; i < 32; i++)  //循环32次，求出每位上的数字
{
if (((n >> i) & 1) == 1)
{
count++;
}

}
return count;
}
``````

`((n >> i) & 1)`，将`n`右移`i`次，`i`从0开始，每次加一，所以`n`从右移1位开始，每次多移一位，因为左右移操作符不会改变原来`n`的值，所以每次向后移动`i`位，就巧妙地得到了`i`位上的数字，在`&1`就能得到每位上的数字

``````int NumberOd1(int n)
{
int count = 0;
while(n)
{
n = n&(n-1);
count++;
}
return count++;
}
``````

2.获取一个整数二进制序列中所有的偶数位和奇数位，分别打印出二进制序列

``````void print(int n)
{
int arr[32] = { 0 };
printf("奇数位：");
for (int i = 1; i < 32; i+=2)
{
printf("%d ", (n>>i)&1);
arr[i] = (n >> i) & 1;

}
printf("\n");
printf("偶数位：");
for (int i = 0; i < 32; i += 2)
{
printf("%d ", (n >> i) & 1);
arr[i] = (n >> i) & 1;
}
printf("\n");

for (int i = 31; i >=0; i--)
{
printf("%d", arr[i]);
}
}
``````

3.两个int（32位）整数m和n的二进制表达中，有多少个位(bit)不同？

``````int compare(int a, int b)
{
int count = 0;
for (int i = 0; i < 32; i++)
{
if (((a >> i) & 1) != ((b >> i) & 1))
{
count++;
}
}
return count;
}
``````

``````int compare(int a, int b)
{
//也可以用异或解决
int tmp = a ^ b;
//统计tmp里1的个数
int count = 0;
for (int i = 0; i < 32; i++)
{
if ((tmp >> i) & 1 == 1)
{
count++;
}
}
return count;
}

``````