1、首先我们来介绍基础的位运算符,下面所提及都是2进制运算情况下:
按位与(&) 同1则1 按位或(|) 有1则1 按位异或(^) 相同为0 相异为1 按位取反(~)相反
来看下面几个例子
int a = 13 & 11;
int b = 13 | 11;
int c = 13 ^ 11;
int d = ~0;
printf("a:%d b:%d c:%d,d:%d",a,b,c,d);
输出的结果如下
2、前面的abc都比较好理解,0取反为什么是-1呢 ?实际上printf打印的%d是补码,在此处引入原码反码补码的概念。
整数在二进制存储时,最高位为符号位,0代表正1代表负,原码,反码,补码的引入是为了解决做减法的问题,正整数的原码补码反码都相同,负数的反码就是他的原码除符号位外,按位取反。在进行相加时,正数+负数转化成正数+负数的反码得以解决问题,负数的补码等于反码+1。
如果想知道0取反后的码,作为补码去打印代表的是哪个数?就要进行还原,最高位代表符号位的8位表示0取反后的该码位1111 1111 ,由于补码=反码+1,该码先-1得到该数的反码1111 1110再求其原码为 1000 0001即打印负1。
这里再举一个例子16位进制下 printf打印32769 会显示多少呢? 已知2的15次方为 32767
所以 32769的二进制为 1000 0000 0000 0001 printf会将其看作是负数,那么这是哪个负数的补码呢?需要进行还原 ,我们知道 负数的补码=反码+1,还原的过程 是减一取反得到那个负数
即对 1000 0000 0000 0000取反(符号位不变) 1111 1111 1111 1111 结果是-32767
因此printf("%d",32767)在16位pc机上 会显示 -32767
3、 >>右移位运算符 <<左移位运算符
对于正数而言,正数的右移相当于除法,右移几位就除以2的几次方,如100>>4 等效 100/2^4,即高位补0,而负数的右移移动的是补码且高位补1,求-1>>1 的值为多少?
-1的补码上面求过了为 1111 1111,向右移动高位补1,因此-1右移多少位都是-1。
左移运算符都是补0,因此相当于乘法,1<<2=2。
4、位运算符的应用:
输入一个数字,计算2进制中1的个数以及改变第k位的值
分析:计算1的个数:将该数字依次右移0至31位,每次都跟1做&运算,为1则count++
举例改变第3位为1 则 | 或上一个0000 0100,改变第3位为0,则& 1111 1011
int main() {
int num = 0;
int count = 0;
scanf("%d", &num);
printf("按位与计算%d二进制中1的位数\n",num);
int i;
for (i = 0; i < 32; i++) {
if (1 == ((num >> i) & 1))
{
count++;
}
}
printf(" %d\n", count);
//改变指定二进制第n位上的值 变成1或者0;
num = k;
printf("输入第k位的值赋值为1\n");
int k = 0;
scanf("%d", &k);
num = num | (1 << k-1);
printf("num的二进制改变第k位为1后的值为 %d \n", num);
printf("输入第k位的值赋值为0");
scanf("%d", &k);
num = k;
num = num & (~(1 << k-1));
printf("num的二进制改变第k位为0后的值为 %d \n", num);
return 0;
}
在这里介绍整型提升以及sizeof的特点
char只有1个字节即8位
// char a=0xb6; a为1011 0110 最高位为1,为负数
// BUT int a=0xb6 为正数
// 同理short b=0xb600 也是一个负数
//sizeof中的式子不参与运算;在进行表达式计算的时候发生整形提升
//printf(" %d", sizeof(a = a + b));
//printf(" %d", a);(此时a的值不发生变化)
//char a=1;
// printf(" %d", sizeof(a + 1)); 返回4,char发生整型提升