文章目录
一、位运算符
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左移运算符
左移运算符<
实例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);
}
if (b > -1)
{
printf("b>-1\n");
}
else
{
printf("b);
}
}
输出结果为:
为什么呢?
a为unsigned short类型,-1为整型,整型类型大,因此直接将a提升为整型的10;因此10>-1;
b为unsigned int类型,-1为整型,同级别:无符号整型>整型;-1转化为无符号整型大约为40多亿,大于10,因此b
窄的符号类型如何变成宽的符号类型呢?
窄变宽:左边补符号位(无符号数左边补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);
}
输出结果为: