位运算

 

#include <stdio.h>
#include <stdlib.h>
//位运算 取反
void main1(){
    unsigned char ch = 15;  //0000 1111
    unsigned char fch = ~ch; //1111 0000 取反运算,取反并不会改变ch的值,赋值运算才会改变(ch = ~ch;)
    unsigned char ffch = ~fch; //0000 1111 再次取反运算,两次取反就变成原来的值了
    printf("%d,%d,%d\n",ch,fch,ffch);  //15,240,15
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//位运算 位与&       1&1->1    0&1,1&0,0&0->0   根据这一特性可以得出以下两种功能
//1、二进制位与0相与,执行清零操作:  0 & 0 ->0  1 & 0->0   与0相与,把第一个操作数全部置为0
//2、二进制位与1相与,保留某些位不变: 0 & 1 ->0  1 & 1 ->1 与1相与 保留第一个操作数不变
//高级用法:与取反运算相结合,可以实现不同类型(char,short,int)数值的最低为清零,还可以实现取余的运算(不用%运算符)
void main2(){
    unsigned char ch = 35;  //0010 0011
    unsigned char ch1 = 0; //0000 0000
    unsigned char ch2 = 15; //0000 1111
    unsigned char ch3 = 240; //1111 0000
    unsigned char ch4 = 60; //0011 1100
    printf("%d\n",ch&ch1);  // 0000 0000 全部清零                 0
    printf("%d\n",ch&ch2);  // 0000 0011 清零高四位,保留低四位    3
    printf("%d\n",ch&ch3);  // 0010 0000 保留高四位,清零低四位`   32
    printf("%d\n",ch&ch4);  // 0010 0000 取出中间四位数   32
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//位运算 位或|    1|1,0|1,1|0 ->1   0|0->0  根据这一特性可以得出以下两种功能
//1、二进制位与1相或,执行置1操作:  0 | 1 ->1  1 | 1->1   与1相或,把第一个操作数全部置为1
//2、二进制位与0相或,保留某些位不变: 0 | 0 ->0   1 | 0 ->1  与0相或 保留第一个操作数不变
void main3(){
    unsigned char ch = 35;  //0010 0011
    unsigned char ch1 = 0; //0000 0000
    unsigned char ch2 = 15; //0000 1111
    unsigned char ch3 = 240; //1111 0000
    unsigned char ch4 = 60; //0011 1100
    printf("%d\n",ch|ch1);  // 0010 0011 全部保持不变              35
    printf("%d\n",ch|ch2);  // 0010 1111 保留高四位,低四位全部为1    47
    printf("%d\n",ch|ch3);  // 1111 0011 高四位全部为1,保留低四位`   243
    printf("%d\n",ch|ch4);  // 0011 1111 中间四位数全部为1,保留收尾两位   63
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//位运算 位异或^     1 ^ 0=1  0 ^ 1=1,相同为0,不同为1 1 ^ 1=0 0 ^ 0=0  根据这一特性可以得出以下两种功能
//1、二进制位与1相异或,发生反转,0变1,1变0:  0 ^ 1 ->1  1 ^ 1->0
//2、二进制位与0相异或,保持位数不变: 0 ^ 0 ->1   1 ^ 0 ->1  与0相异或 保持位数不变:
void main4(){
    unsigned char ch = 35;  //0010 0011
    unsigned char ch1 = 0;   //0000 0000
    unsigned char ch2 = 15; //0000 1111
    unsigned char ch3 = 240; //1111 0000
    unsigned char ch4 = 60; //0011 1100
    printf("%d\n",ch^ch1);  // 0010 0011 全部保持不变      35
    printf("%d\n",ch^ch2);  // 0010 1100  前四位保持不变,后四位发生反转   44
    printf("%d\n",ch^ch3);  // 1101 0011 前四位发生反转,后四位保持不变   211
    printf("%d\n",ch^ch4);  // 0001 1111 中间四位反转,保持首尾两位不变   31
}
//异或可以用于交换变量,不借助中间变量,一般用于嵌入式开发和需要节约内存的场合
//           x = x ^ y;    y = x ^ y;  x = x ^ y;  记住  不会溢出
//类似于:   x = x + y;    y = x - y;  x = x ^ y;  类比记忆  可能会溢出
//x = x * y; y = x / y; x = x / y; 可能会溢出
void main5(){ unsigned char x =10; unsigned char y= 20; x = x ^ y; y = x ^ y; x = x ^ y; // x = x + y; y = x - y; x = x ^ y; printf("%d,%d\n",x,y); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /*移位运算表达式的基本形式为: A << n; *//*左移*//* 或 A >> n; *//*右移*//* A称为操作数,其必须为数字型变量或数字型常量,此处的数字型包括整型和char型,A中存储的0、1序列向左或右移动n位, 移动后的值作为整个表达式的输出,执行移位运算并不改变操作数A的值。存储在寄存器中*/ void main6(){ unsigned char ch = 1; //0000 0001 1 printf("%d\n",ch << 1); // 0000 0010 2 printf("%d\n",ch << 2); // 0000 0100 4 //左移一位就乘以2,计算结果在寄存器中,不会改变ch的值 printf("%d\n",ch << 7); // 1000 0000 128 printf("%d\n",ch); // 0000 0001 printf("%d\n",ch << 8); // 10000 0000 0 左移8位溢出了,读取了无效数据 } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void main(){ //位运算的复合运算 char ch = 1; ch >>=2 ; //ch = ch >> 2; ch <<=2 ; //ch = ch << 2; ch &=2 ; //ch = ch & 2; ch |=2 ; //ch = ch | 2; ch ^=2 ; //ch = ch ^ 2; ch = ~ch; }

 

1、类型不匹配:
无符号数据在进行位运算时,类型不匹配时,需要进行自动类型转换
低字节向高字节转换时,会自动填充 0


有符号数据在进行位运算时,类型不匹配时,需要进行自动类型转换
低字节向高字节转换时,
正数会按照符号位自动填充 0
负数会按照符号位自动填充 1 位运算操作的是补码/
2、移位运算
左移时,右边都是填充0
右移时:无符号数据,左边填充0
有符号数据:正数按照符号位填充0
负数按照符号位填充1
3、 ~ | & ^ 不关心操作数的符号,符号位会被当做普通的0和1处理

#include <stdio.h>
int func(x){
    int countx = 0;
    while(x){
        countx ++;
        x= x & (x-1);  //实际上就是求二进制数有多少个 1
    }
    return countx;
}
void main(){
    int x=9999;  //100111 0000 1111  用除K取余法转换成二进制
    printf("%d\n",func(x));  //8
};

 输入一个整数,打印其补码,用位运算实现


#include <stdio.h>
#include <stdlib.h>
//输入一个整数,打印其补码,用位运算实现
//0010 1110     0000 0001    0000 1111  0011 1101  任意一个整数的补码
//1000 0000     0000 0000    0000 0000  0000  0000   在计算机内部,补码是低字节位数在前面,让其与这个数相与,取出第一位数
 void main(){
    int num;
    scanf("%d",&num);
    int data = 1 << 31;  //构造被与数  1000 0000     0000 0000    0000 0000  0000  0000
    for (int i = 0; i < 32; ++i) {
        printf("%c",((num & data)? '1': '0'));
        num <<=1;  //num再右移一位
        if((i+1) % 4 == 0){
            printf("\n");
        }
    }
}

 

#include <stdio.h>
#include <stdlib.h>
//输入一个整数,打印其源码补码,用结构体实现
struct bits{    //根据结构体对齐原则,此结构体占一个字节
    unsigned char b1 : 1;
    unsigned char b2 : 1;
    unsigned char b3 : 1;
    unsigned char b4 : 1;
    unsigned char b5 : 1;
    unsigned char b6 : 1;
    unsigned char b7 : 1;
    unsigned char b8 : 1;
};
 void main(){
   struct bits *pBits = (struct bits *)malloc(sizeof(struct bits) * 4); //分配四个字节,每一个字节是一个结构体
   int *pInt = (int *)pBits; //把四个字节的结构体// 共享内存  按照int的解析接受整数的输入
   *pInt =0; //初始化数据
   scanf("%d",pInt);
   for(int i = 3 ; i >= 0 ; i-- ){  //低字节在前,高字节在后,从后面开始循环
       printf("%d%d%d%d %d%d%d%d \n",
               pBits[i].b8,  //按照结构体解析,输出每一位数字,每个i是一个结构体
               pBits[i].b7,
               pBits[i].b6,
               pBits[i].b5,
               pBits[i].b4,
               pBits[i].b3,
               pBits[i].b2,
               pBits[i].b1
               );
   }

}

 

输入一个浮点数,打印补码

#include <stdio.h>
#include <stdlib.h>
//输入一个浮点数,打印补码
//第一种方法:自动分配浮点数据内存,转换地址成 unsigned char类型,共享内存,按照unsigned char 类型解析,取出里面的每一位
void main1(){
    float f;
    scanf("%f",&f); //接收浮点数据输入
    //浮点数据也是按照4个字节存储的二进制数,现在定义一个 unsigned char的指针类型,取出里面的每一个字节,再利用位运算&,取出每个字节中的每一位
    //unsigned char *p = (unsigned char *)malloc(sizeof(unsigned char) * 4);
    unsigned char *p = (unsigned char *)&f;  //把f的地址存储在p指针中,并按照unsigned char来解析数据,共享内存
    for (int i = 3; i >=0 ; i--) {   //高字节在前,低字节在后,遍历浮点数据的每一个字节
        unsigned char ch= p[i];   //p[i]是这个字节的首地址,&p[i]是这个字节第一位的首地址
        for (int j = 7; j >=0 ; j-- ) {    //高位在前,低位在后,遍历每一个字节中的每一位
            if(ch & (1 << j)){    //1 <<j 把第j位置为1,与ch相与,从高位到低位,依次取出每一位的值
                printf("%c",'1');
            } else{
                printf("%c",'0');
            }
        }
        printf("\n"); //一个字节换行
    }
}
//第二种方法,手动分配浮点数据的内存
void main(){
    //浮点数据也是按照4个字节存储的二进制数,现在定义一个 unsigned char的指针类型,取出里面的每一个字节,再利用位运算&,取出每个字节中的每一位
    unsigned char *p = (unsigned char *)malloc(sizeof(unsigned char) * 4);  //分配四个字节的内存,存储浮点数的二进制数
    scanf("%f",p); //接收浮点二进制数输入,二进制已经定型,后面按照unsigned char的类型去解析
    for (int i = 3; i >=0 ; i--) {   //高字节在前,低字节在后,遍历浮点数据的每一个字节
        unsigned char ch= p[i];   //p[i]是这个字节的首地址,&p[i]是这个字节第一位的首地址,unsigned char的类型去解析数据
        for (int j = 7; j >=0 ; j-- ) {    //高位在前,低位在后,遍历每一个字节中的每一位
            if(ch & (1 << j)){    //1 <<j 把第j位置为1,与ch相与,从高位到低位,依次取出每一位的值
                printf("%c",'1');
            } else{
                printf("%c",'0');
            }
        }
        printf("\n"); //一个字节换行
    }
}

 



 


posted @ 2019-08-13 15:44  Coding_Changes_LIfe  阅读(243)  评论(0编辑  收藏  举报