C语言: 位操作符与移位操作符的详解

目录

1.分类

2.  ⼆进制和进制转换

2.1 2进制转10进制

2.2 十进制转二进制的计算方法

2.3 二进制转八进制的计算方法

2.4 二进制转十六进制的计算方法

3. 原码、反码、补码

4. 移位操作符

4. 位操作符:&、|、^、~

5.计算一个整数转换为二进制时,出现了几次1?

5.1 通常方法:通过不断%2看其余数是否为1,再不断/2把二进制数右移

5.2 特殊方法


1.分类

移位操作符:<<,>>。

位操作符:& | ^ ~。

2.  ⼆进制和进制转换

在了解这些操作符具体如何使用之前,我们先了解进制的概念,其实我们经常能听到2进制、8进制、10进制、16进制这样的讲法,那是什么意思呢?其实2进制、8进 制、10进制、16进制是数值的不同表⽰形式⽽已。

比如13的不同进制的表达:

13的二进制:1101

13的八进制:15

13的十六进制:d

13的十进制:13

 它们所表达的都是十进制的“13”这个数,不过是用不同的进位方式,来形成不同的数字

比如我们在生活中的十进制就是这样的:

• 10进制中满10进1

• 10进制的数字每⼀位都是0~9的数字组成

转换成二进制,就是这样的:

• 2进制中满2进1

• 2进制的数字每⼀位都是0~1的数字组成

 13这个数通过二进制转换,就变成了1101这个数。

2.1 2进制转10进制

10进制从个位开始,每一位的权重为10^{0}  , 10^{1} , 10^{2} , 10^{3} ..

这里拿123举例

C语言: 位操作符与移位操作符的详解_第1张图片

2进制和10进制是类似的,只不过2进制的每⼀位的权重,从右向左是: 2^{0} ,2^{1} ,2^{2} ...

这里拿13举例

C语言: 位操作符与移位操作符的详解_第2张图片

得出1101

用权重图能直观地感受到数是如何通过不同权重来进位的

2.2 十进制转二进制的计算方法

举例 十进制125

C语言: 位操作符与移位操作符的详解_第3张图片

用小学初次学习除法的方法直观的算出。

2.3 二进制转八进制的计算方法

8进制的数字每⼀位是0~7的,0~7的数字,各⾃写成2进制,最多有3个2进制位就⾜够了,从最右端开始向左计算,每三位权重二进制的数,转化为一位权重8进制的数

C语言: 位操作符与移位操作符的详解_第4张图片

2.4 二进制转十六进制的计算方法

16进制的数字每⼀位是0~9,a ~f 的,0~9,a ~f的数字,各⾃写成2进制,最多有4个2进制位就⾜够了,从最右端开始向左计算,每四位权重二进制的数,转化为一位权重16进制的数

C语言: 位操作符与移位操作符的详解_第5张图片

3. 原码、反码、补码

整数的2进制表⽰⽅法有三种,即原码、反码和补码

有符号整数的三种表⽰⽅法均有符号位和数值位两部分

2进制序列中,最⾼位的1位是被当做符号 位,剩余的都是数值位

符号位都是⽤0表⽰“正”,⽤1表⽰“负”。

正整数的原、反、补码都相同。

负整数则各不相同

原码:直接将数值按照正负数的形式翻译成⼆进制得到的就是原码。

反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。

补码:反码+1就得到补码。

注意:反码得到原码也是可以使⽤:取反,+1的操作

 对于整形来说:数据存放内存中其实存放的是补码。

为什么呢?这里是鹏哥的解释

4. 移位操作符

左移操作符:<<

右移操作符:>>

只有整数才能使用移位操作符


<


#include 
int main()
{
 int num = 10;
 int n = num<<1;
 printf("n= %d\n", n);
 printf("num= %d\n", num);
 return 0;
}

C语言: 位操作符与移位操作符的详解_第6张图片


>>k:二进制数向右移动k格,出格的去掉,空的补0


⾸先右移运算分两种:

1. 逻辑右移:左边⽤0填充,右边丢弃

2. 算术右移:左边⽤原该值的符号位填充,右边丢弃(绝大多数编译器所使用的)

 vs用的是算数右

#include 
int main()
{
 int num = 10;
 int n = num>>1;
 printf("n= %d\n", n);
 printf("num= %d\n", num);
 return 0;
}

C语言: 位操作符与移位操作符的详解_第7张图片

注意:对于移位运算符,不要移动负数位,这个是标准未定义的。

比如 "n>>-1;"

4. 位操作符:&、|、^、~

& :按位只有同时为1,结果为1,否则0

|:按位只要有1,结果为1,否则为0

^: 按位相同为0,不相同为1

~:按位全部取反

#include 
int main()
{
 int num1 = -3;
 int num2 = 5;
 printf("%d\n", num1 & num2);
 printf("%d\n", num1 | num2);
 printf("%d\n", num1 ^ num2);
 printf("%d\n", ~0);
 return 0;
}

 C语言: 位操作符与移位操作符的详解_第8张图片

重点:如何不创造第三个变量(临时变量)实现两个变量的转换?

#include 
int main()
{
 int a = 10;
 int b = 20;
 a = a^b;
 b = a^b;
 a = a^b;
 printf("a = %d b = %d\n", a, b);
 return 0;
}

C语言: 位操作符与移位操作符的详解_第9张图片

这里关于^的用法有几点特殊说明:

a^a = 0;

a^0 = a;

在........

a = a^b;
 b = a^b;
 a = a^b;

.........中

a^b可以看作一份密码,将其赋给a,成为a`

再令b = a^b 也就是b = a` ^b = a^a^b = a,成功给b赋予a的原值,成为b`

最后 a = a^b 也就是a= a` ^ b` = a^b^a = 0^b = b

完成对a和b值的转换

或者有另一个 理解:

a ^ b = c     同时满足 a^c = b b^c = a

则 a(c) = a^b

b(a) = a(c)^b

a(b) = a(c)^b(a)

完成对a和b值的转换

5.计算一个整数转换为二进制时,出现了几次1?

5.1 通常方法:通过不断%2看其余数是否为1,再不断/2把二进制数右移

int count_one_bit(unsigned int n)
{
	int count = 0;
	while (n)
	{
		if (n % 2 == 1)
			count++;
		n = n / 2;
	}
	return count;
}

int main()
{
	int num = 0;
	scanf("%d", &num);
	//求一个整数存储在内存中的二进制中1的个数
	int n = count_one_bit(num);
	printf("%d\n", n);

    return 0;
}

5.2 特殊方法

int count_one_bit(int n)
{
	int count = 0;
	while (n)
	{
		n = n & (n - 1);
		count++;
	}
	return count;
}

int main()
{
	int num = 0;
	scanf("%d", &num);
	//求一个整数存储在内存中的二进制中1的个数
	int n = count_one_bit(num);
    printf("%d\n", n);

	return 0;
}

n=n&(n-1)是个特殊的等式,它能够将去掉一次最右边的1,我们不进行循环,直到数为0为止

//n = n&(n-1)
//效果:把n的二进制中最右边的1去掉了
// 
//n=15
//1111 - n
//1110 - n-1
//1110 - n
//1101 - n-1
//1100 - n
//1011 - n-1
//1000 - n
//0111 - n-1
//0000 - n

感谢你能看到这里

你可能感兴趣的:(java,前端,javascript)