位运算

2020-04-23  本文已影响0人  晓晓桑

16进制 地址形式
0 1 2 4 5 6 7 8 9 A B C D E F
F是15
0x:16进制标志
2进制:内存存储数据
0 1

进制转换

1.基数相加法
2.反转取余法
这两种方法都能单独转,但是为了计算方便,一般是
10进制转其他进制:反转取余法
其他进制转10进制:基数相加法

1.基数相加法
2.反转取余法

转几进制就除以几
234 转成8进制:


image.png
3.进制互相转换
image.png

16-2


image.png

2-16


image.png

位操作

位操作的两种方式:位运算符、位字段
注意:位运算只支持整数

~:按位取反

正数:补码是本身
负数:补码:数据位按位取反再加1(符号不变)
注意⚠️:最高位是符号位,不参与按位取反加一中的取反

#include "c3.h"
int main(int argc, char *argv[]) {

    //分析:
    //整数按照补码形式进行存储的
    //正数的补码是本身,负数的数据位补码是按位取反再加1
    //负数最高位存储是1,正式最高位存储是0
    //-123二进制是:1(符号位) 111 1011 ,按位取反加1:1(符号位不变)000 0100,
    // 再加1,1000 0101,也就是-123在内存中存储的数据。
    //b的话就是a的存取取反:即1000 0101取反0111 1010
    // 0111 1010:122
    char a = -123;
    char b = ~a;
    printf("%d\n", b);//122

    // --------------------
    //123在内存中的存储是:0(符号位) 111 1011
    //取反得到b:1 000 0100
    //b的存储数据是1 000 0100,那么10进制数就是:先-1,再按位取反
    //即:1 000 0011,再按位取反:0 0111 1100:即124,符号位是0 则是-124
    char c = 123;
    char d = ~c;
    printf("%d\n", d);//-124
    return 0;
}

&:按位与

只有1&1 =1,
其他都是0
1010 1111&1100 1010
得:1000 1010

#include "c3.h"

int main(int argc, char *argv[]) {

    //分析:79的二进制:0 100 1111 ,-23的二进制:1 001 0111
    //-23在内存中存取数据是:数据位按位取反+1 :1 110 1001
    //0 100 1111 & 1 110 1001 得 0 100 1001 得:+73
    char a = 79;
    char b = -23;
    char c = a & b;
    printf("%d\n", c);//73
    return 0;
}

|:按位或

只有0|0得0,
其他都是1
1010 1111 | 1100 1010
得:1110 1111

#include "c3.h"

int main(int argc, char *argv[]) {

    //分析:79的二进制:0 100 1111 ,-23的二进制:1 001 0111
    //-23在内存中存取数据是:数据位按位取反+1 :1 110 1001
    //0 100 1111 | 1 110 1001 得 1 110 1111
    // 因为上面存储的数据是负数,所以得到真正的数据:-1 按位取反
    //即:1 0110 1110 取反:1 0001 0001,即-17
    char a = 79;
    char b = -23;
    char c = a | b;
    printf("%d\n", c);//-17
  
    return 0;
}

^:按位异或

不同为1,
相同为0
1010 1111 ^ 1100 1010
得:0110 0101
注意:C中pow是平方,sqrt是开方

#include "c3.h"

int main(int argc, char *argv[]) {

    //分析:79的二进制:0 100 1111 ,-23的二进制:1 001 0111
    //-23在内存中存取数据是:数据位按位取反+1 :1 110 1001
    //0 100 1111 ^ 
      1 110 1001 得 1010 0110
    // 因为是负数,所以真正的数据是-1 取反
    //即  1 010 0101 取反:1 101 1010 得-90
    char a = 79;
    char b = -23;
    char c = a ^b;
    printf("%d\n", c);//-90

    return 0;
}

<<和>> :移位运算符

1000 0101 位左移两位
image.png
int main(int argc, char *argv[]) {

    //分析:a的存储形式就是他本身:0010 1101
    //坐移动两位:变成:1011 0100
    //因为1 所以是负数:-1取反:所以是1100 1100 即-76
    char a = 45;
    char b = a << 2;
    printf("%d\n", b);//-76
    return 0;
}
1000 0101 位右移两位

如果正数:位右移2位,最高位补俩0
如意负数:位右移2位,有的系统补俩0,有的系统补俩1(windows是补11,macbook pro测试也是补11)

//正数的时候:
int main(int argc, char *argv[]) {

    //分析:a的存储形式就是他本身:0010 1101
    //坐移动两位:变成:0000 1011 即11
    char a = 45;
    char b = a >>2;
    printf("%d\n", b);//11

    return 0;
}
//负数的时候,我的电脑是最高位补1
#include "c3.h"
int main(int argc, char *argv[]) {

    //分析:a的存储形式就是他的取反+1:
    // -45:1010 1101,取反+1:1101 0011
    //坐移动两位:变成:1111 0100
    //因为是负数,1111 0100 是他的存储数据,他真正的数据是:
    // -1 再取反:-1: 1111 0011 取反:1000 1100 即-12
    char a = -45;
    char b = a >>2;
    printf("%d\n", b);//-12

    return 0;
}

技巧⚠️:

a<<n,相当于乘以2的n次幂;
a>>n,a如果是非负数,相当于除以(/取整)2的n次幂
位运算速度远远大于普通运算

#include "c3.h"

int main(int argc, char *argv[]) {

    char a = 6;
    char b = a << 3;//a左移动2位,相当于,6*2^3=48
    printf("%d\n", b);//48 :

    char c = 48;
    char d = c >> 3;//非负数a右移动3位,相当于,48/(2^3)
    printf("%d\n", d);//6
    return 0;
}

&=、|=、^=、>>=、<<=

跟+= 、-=一样。
a^=b :a=a^b;
...

2.位字段

这个方法移植性不是很好,位运算完全可以实现字段的所有功能,所以位字段了解为主。


image.png
上一篇 下一篇

猜你喜欢

热点阅读