文章目录
一、位运算符1.1按位取反1.2按位与1.3按位或1.4按位异或
二、移位运算符2.1左移运算符2.2右移运算符
三、类型转换详解四、多种位运算实例分析
一、位运算符
1.1按位取反
按位取反~:作用是按位将0变成1,1变成0;
如:二进制10011010取反后
~(10011010)——> 01100101//原码
实例1: 先按位取反,但是在计算机中存储需要将原码按照补码方式存储,因此符号位不变再取反+1。
void test()
{
int num = 2;
//0000 0010 —>1111 1101原码
//—>取反1000 0010 加1—>1000 0011 —>-3
printf("%d\n",~num);
}
输出结果为: 实例2: 此时我们需要了解各种类型数据的取值范围。unsigned char的取值范围为:0—255,我们看如下例子。
void test()
{
unsigned char a = 2;//0000 0010
unsigned char b = ~a;//-3,但为无符号char类型,1000 0011—>
//1111 1100(负数转换变为正数)—>(正数)1111 1101—>253
printf("a = %d\n",a);//2
printf("b = %d\n",b);
}
输出结果:a为正数不变;b与上面一样2的补码为-3,但此时为unsigned char类型数据需要进行再次转换,计算机中的负数以二进制补码表示,补码 = 二进制数(原码)的反码 + 1。
1.2按位与
按位与&:作用是按位与,全真为真(1),有一个假即为假(0);
如:二进制数10001101按位与后
10101010——>10001000
实例1: 判断任意一个数字的奇偶性。任意一个数字与上1,结果为1,是奇数;为0,是偶数;
随意写一个数字10010101与上1
00000001
00000001//结果为1,是奇数;为0,是偶数;
简单测试一下:
void test()
{
int num = 123;
if ((num&1) == 0)//与上1
{
printf("num为偶数\n");
}
else
{
printf("num为奇数\n");
}
}
测试成功:
1.3按位或
按位或 |:作用是作用是按位或,全真为真(1),有一个真(1)也为真,全假才为假(0);
如:二进制数10010100按位或后
01110010——>11110110
实例1: 按位或操作
void test()
{
int num1 = 5;
int num2 = 3;
printf("num1|num2 = %d\n",num1|num2);//0101
//0011—>0111—>7
}
测试结果:为7
1.4按位异或
按位异或^:作用是按位异或:两个不一样为真,输出1;两个一样,为假,输出0;
按位异或:相同为0,不同为1;10010101 进行按位异或
00011100——>10001001
实例1:实现两个数交换的多种方法 方式1:使用临时变量方法即可完成交换
int temp = num1;
num1 = num2;
num2 = temp;
方式2:利用按位异或实现两个数的交换(不使用临时变量交换的方法)
void test()//利用按位异或实现两个数的交换
{
int num1 = 10;
int num2 = 20;
printf("交换前:\n",num1);
printf("num1 = %d\n",num1);
printf("num2 = %d\n",num2);
num1 = num1^num2;
num2 = num1^num2;
num1 = num1^num2;
printf("交换后:\n",num1);
printf("num1 = %d\n",num1);
printf("num2 = %d\n",num2);
}
方式3:我们将其中这三行修改也可以实现2个数交换,输出结果是相同的。
num1 = num1 + num2;
num2 = num1 - num2;
num1 = num1 - num2;
最后测试结果都测试成功。
二、移位运算符
2.1左移运算符
左移运算符<<:将其操作数的值的每位向左移动,移动的位数由其右侧操作数指定。空出来的位用0填充,并且丢弃移出左侧操作数末端的位。左移X次代表乘以2^X次方。 实例1:左移X次代表乘以2^X次方。
void test()//左移运算符
{
int num = 10;
printf("num = %d\n",num<<2);//相当于乘4
}
输出结果:
2.2右移运算符
右移运算符>>:将其左侧的操作数的值每位向右移动,移动的位数由其右侧的操作数指定。丢弃移出左侧操作数有段的位。左移X次代表除以2^X次方。 对于unsigned类型,使用0填充左端空出的位。对于有符号类型,结果依赖于机器,空出来的位可能用0填充,或者使用符号(最左端)位的副本填充。不同的机器可能有不同的结果。 正数则左边补0,负数标准没有规定在左边补充的数字,分为逻辑右移和算术右移,具体由编译器决定。windows平台和gcc采取算术右移即负数补1。 实例1:右移X次代表除以2^X次方。
void test()//右移运算符
{
int num = 10;
printf("num = %d\n",num>>1);//相当于除2
}
输出结果:
三、类型转换详解
类型转换: 当参加一个运算的数据的类型不同时运算需要类型转换。首先变量的数据类型是可以转换的。转换的方法有两种,一种是显示转换,另一种是隐式转换。 显示转换:
char a = (char)200;//显示转换,-56 -(256-200)
int b = (int)12.5;//显示转换 12
隐式转换:
char c = 100;
int d = c + 25;//隐式转换,自动转换为整型
我们还需要了解一下各种类型数据范围,为什么呢? 类型转换时,就像我们把1个字节东西放入4个字节的盒子时,是没有问题的;但是,如果把4个字节东西放入1个字节盒子里时,放不下去自然要进行相应转化才能放进去。因此,我们就要了解一下各种数据类型范围:
转换规则: 各种数据类型范围: 案例1:类型转换1。
void test()
{
char a = -1;//-1
char b = 255;//-1
unsigned char c = a;//255
unsigned char d = b;//255
int e = a;//-1
int f = b;//-1
unsigned int g = a;//2^32-1
unsigned int h = b;//2^32-1
printf("%d %d %d %d\n",a,b,c,d);
printf("%d %d %u %u\n",e,f,g,h);
}
输出结果为:如下 ①char类型的范围为-127~128,所以a还是-1,但是b自动转换为255了。 ②unsigned char类型范围为:0-255,所以c,d都为255; ③int类型范围为-几亿~+几亿,范围足够大,所以e,f还是-1; ④unsigned int范围为0~4294967295,因此需要将-1转换为4296967295。 案例2:类型转换2。
void test()
{
unsigned short a = 10;
unsigned int b = 10;
if (a > -1)//a提升为整型10
{
printf("a>-1\n");
}
else
{
printf("a<-1\n");
}
if (b > -1)
{
printf("b>-1\n");
}
else
{
printf("b<-1\n");
}
}
输出结果为: 为什么呢? a为unsigned short类型,-1为整型,整型类型大,因此直接将a提升为整型的10;因此10>-1; b为unsigned int类型,-1为整型,同级别:无符号整型>整型;-1转化为无符号整型大约为40多亿,大于10,因此b<-1;
窄的符号类型如何变成宽的符号类型呢? 窄变宽:左边补符号位(无符号数左边补0)。 案例2:类型转换3。
void test()
{
int d = 200;
char b = 200;
b = (char)d;//-56
d = (int)b;//-56
printf("%d\n",d);
}
输出结果:b为char类型,存储不下200,需要转换为-56; d为int类型,可以存储-56,最后输出-56;
四、多种位运算实例分析
综合实例1: 常见的二进制位的变换操作:定符号、定数字、构造数字。 综合实例2:(10<<8)|2 我们用代码验证一下:
void test()
{
int num = 10;
printf("num = %d\n",num<<8|2);
}
输出结果为: