操作符与二进制

文章目录

前言:

一、计算机中的二进制

1.整数的分类

2.原码,反码和补码

二、操作符

1.移位操作符

1.1 左移操作符:<<

1.2  右移操作符:>>

1.2.1 逻辑右移

1.2.2 算术右移

2. 位操作符

2.1 按位与操作符:&

2.2 按位或操作符:|

2.3 按位异或操作符:^

2.4 按位取反操作符: ~

三、拓展与应用

1. 按位异或:^

2.移位操作符与按位与


前言:

本篇主要针对C语言中对二进制进行处理的一些操作符,又由于在内存中存储的是整数的补码,因此是对补码进行操作。

一、计算机中的二进制

我们知道一个整数有原码,反码和补码,在计算机内存中整数的存储形式是其二进制补码,那我们就讨论一下不同的整数是怎么存储在计算机中的,且是在32位计算机的环境下。

1.整数的分类

计算机默认整数位有符号整数,所以在创建无符号整数时需要用unsigned int

对于有符号整数在32位计算机中

符号位                                                       数值位

最高位为符号位,其余位位数值位,且正数符号位记为0负数记为1。

2.原码,反码和补码

(1)对于正数:原码,反码和补码都一样

举个例子,正整数15在32位计算机中

原码01111
反码01111
补码01111

由于表格大小限制,只展示了符号位与有意义的数值位,中间的0省略了。

(2)对于负整数:原码,反码和补码都不一样,反码就是原码取反,而补码就是对反码加1,且满二进一,在整个过程中,符号位保持不变

举个例子,对于负整数15

原码1000000...00000001111
反码1111111...11111110000
补码1111111...11111110001

(3)无符号整数:原码,反码和补码都一样

这里不再举例说明。

*再说明一点:比如在电脑上打印一个整数,则要将补码转化为原码来计算整数的值,而补码转原码,只需要将补码先取反,再加1

二、操作符

1.移位操作符

1.1 左移操作符<<

(1)移位规则:左边抛弃,右边补零

(2)举个例子:对正整数6,进行左移1的操作

代码示例

#include<stdio.h>
int main()
{
	int a = 6;
	int b = a << 1;
	printf("%d\n", b);
	return 0;
}

运行结果:12

(3)结合前面所讲分析

对于正整数a=6:a<<1

                           数值位
补码000000...0000000110
                                                进行左移1位
000000...0000000110
                                          左边抛弃,右边补零
0000...000000001100

所以b的补码为:0000 0000 0000 0000 0000 0000 0000 1100

再转化为原码为:0000 0000 0000 0000 0000 0000 0000 1100

即 打印出b=8+4=12

1.2  右移操作符>>

原理同左移操作符相似,因此下面简单说明

1.2.1 逻辑右移

移位规则:左边补零,右边抛弃

1.2.2 算术右移

移位规则:左边补原来的符号位,右边抛弃

我所用的vs2022编译环境下,采用算术右移,因此下面展示的结果为算术右移的结果。

(1)首先拿正整数6来看:

代码展示

#include<stdio.h>
int main()
{
	int a = 6;
	int b = a >> 1;
	printf("%d\n", b);
	return 0;
}

运行结果:3

(2)再拿负数6来看:

代码展示

#include<stdio.h>
int main()
{
	int a =-6;
	int b = a >> 1;
	printf("%d\n", b);
	return 0;
}

运行结果:-3

对负数6计算逐过程分析:

                            数值位
原码100000...00000110
反码111111...11111001
补码111111...11111010
                                                   补码右移1位
111111...11111010
                                     左边补原来的符号位,右边抛弃
补码1111111...1111101
                                                      先取反
反码1000000...0000010
                                                      再加1
原码1000000...0000011

所以得到的原码为1000 0000 0000 0000 0000 0000 0000 0011

即为整数:-3

2. 位操作符

2.1 按位与操作符:&

(1)操作规则:将两个数的补码的相对的位进行计算,对应位同时为1则记为1,有0则记为0

(2)举例:

直接看代码

#include<stdio.h>
int main()
{
	int a =3;
	int b = -5;
	int z = a & b;
	printf("%d\n", z);
	return 0;
}

运行结果:3

(3)分析:

                            数值位

a的补码

00000...0000000011
b的补码11111...1111111011
                                                     按位或操作
z的补码00000...0000000011
z的原码00000...0000000011

所以z=3。

2.2 按位或操作符:|

(1)操作规则:补码的对应位只要有1则记为1,同时为0记为0

(2)举例:

直接看代码

#include<stdio.h>
int main()
{
	int a =3;
	int b = -5;
	int z = a | b;
	printf("%d\n", z);
	return 0;
}

运行结果:-5

(3)分析:

                       数值位
a的补码00000...00000011
b的补码11111...11111011
                                                    按位或操作
z的补码11111...11111011
z的原码10000...00000101

所以z= -5

2.3 按位异或操作符:^

(1)操作规则:补码的对应位相同则记为0,相异则记为1

  (2)举例:

直接看代码

#include<stdio.h>
int main()
{
	int a =6;
	int b = -5;
	int z = a ^ b;
	printf("%d\n", z);
	return 0;
}

运行结果:-3

(3)分析:

                       数值位
a的补码00000...00000110
b的补码11111...11111011
                                                  按位异或操作
z的补码11111...11111101
z的原码10000...0000001

1

所以z= -3

2.4 按位取反操作符: ~

(1)操作规则:补码对应位原来为1则记为0,原来为0则记为1

  (2)举例:

直接看代码

#include<stdio.h>
int main()
{
	int a =5;
	int z = ~ a;
	printf("%d\n", z);
	return 0;
}

运行结果:-6

(3)分析:

                               数值位
a的补码00000...00000101
                                                    按位取反操作
z的补码11111...11111010
z的原码10000...00000110

所以z=-6

三、拓展与应用

1. 按位异或:^

上面我们已经知道,按位异或:相同为0,相异为1。

所以有:a^a=0

               a^0=a

且满足交换律:a^a^b=a^b^a=b

练习:不引入第三个变量,交换两个数的值。

代码展示

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	int a, b;
	scanf("%d %d", &a, &b);
	printf("交换前a=%d b=%d\n", a, b);
	a = a ^ b;
	b = a ^ b;
	a = a ^ b;
	printf("交换后a=%d b=%d\n", a, b);
	return 0;
}

运行结果:

2.移位操作符与按位与

练习:编写代码实现:求⼀个整数存储在内存中的⼆进制中1的个数。

代码展示

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int count_1_of_n(int n)
{
	int i = 0;
	int count = 0;//用来统计1的个数
	for (i = 0; i <32 ; i++)//需要n的二进制位右移31次
	{
		if (((n >> i) & 1) == 1)//只有n最右边的一位为1时,按位与1才等于1。
		{
			count++;
		}
	}
	return count;
}
int main()
{
	int n;
	scanf("%d", &n);
	int k = count_1_of_n(n);
	printf("%d\n", k);
	return 0;
}

运行结果

7的二进制补码为:0000 0000 0000 0000 0000 0000 0000 0111

其中有3个1

更优的算法:

原理:

设n=15(为了方便,只写出为1的二进制位),然后n=n&(n-1)

补码的变化:

n1111
n-11110
                                      第一次       :    n&(n-1)    ;   count++
n1110
n-11101
                                      第二次      :      n&(n-1)    ;   count++
n1100
n-11011
                                       第三次      :   n&(n-1)      ;   count++
n1000
n-10111
                                      第四次      :    n&(n-1)      ;   count++
n0000

代码展示

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int count_1_of_n(int n);//函数声明
int main()
{
	int n;
	scanf("%d", &n);
	int k = count_1_of_n(n);
	printf("%d\n", k);
	return 0;
}
int count_1_of_n(int n)
{
	int count = 0;
	while (n)
	{
		n = n & (n - 1);
		count++;
	}
	return count;
}

运行结果

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值