位运算
#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"); //一个字节换行
}
}

浙公网安备 33010602011771号