C语言:部分操作符讲解

本文详细介绍了32位CPU下整数的原码、反码和补码表示方法,以及左移、右移操作符的工作原理,包括逻辑右移和算数右移的区别。此外,还讨论了位操作符(按位与、按位或、按位异或)的应用,以及整形提升和算术转换的概念。
摘要由CSDN通过智能技术生成

整形的原反补:

此章节是在32位cpu地址线下讲解。

整数的二进制表示方法一共有三种,即原码,反码,补码

有符号整数的三种二进制表示方法又有符号位数值位两部分,最高位的1被当做符号位,其余的都是数值位。如果最高位是1,就代表这个数是负数,如果是0,则这个为是正数。

 上面这个二进制翻译为十进制是-1。 

无符号整数的最高位是数值位。

 原码:就是将整数按照正负数的形式翻译成二进制得到的就是原码。

1.正整数的原码,反码,补码都是相同的。

2.负整数的原码,反码,补码不相同。

负整数的反码:将原码的符号位不变其余数值位按位取反(0变为1,1变为0)。

负整数的补码:将反码+1。

将补码取反+1也能够得到原码

对于整形来说,数据存放在内存中真实存放的是补码。 

对于整形数据存放在内存中存放的是此整形的补码,因为在使用补码时,可将符号位和数值域统一处理,同时加法和减法也可以统一处理(cpu中只有加法器),而且补码和原码进行转化时不需要额外的硬件电路。

所以我们下面操作符操作的都是将整形翻译为二进制的补码形式。

1.位移操作符:

其操作数只能是整数。

1.1<<左移操作符:

左移操作符的规则:左边抛弃,右边补0

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

运行结果:

为什么会得到这个结果呢,我用图像演示左移操作符:左边丢弃1位,右边补0。(一般左移操作符有乘2的效果)

1.2 右移操作符:

 右移操作符规则有两种:

1.逻辑右移:右边丢弃,左边补0.

2.算数右移:右边丢弃,左边补符号位

1.2.1逻辑右移:

右边丢弃1位,左边补0。

 逻辑右移比较少见,大部分编译器都是算数右移。

1.2.2算数右移:

右边丢弃一位,左边补符号位。

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

运行结果:(一般右移操作符有除2的效果)

注意:移位操作符不能移动负数位,这是标椎未定义的,左移操作符移动一位,一般对操作数会有乘2的效果,右移操作符移动一位,一般对操作数有除2的效果。

2.位操作符:

 位操作符有:

&——按位与(有0为0,全1为1)

|——按位或(有1为1,全0为0)

^——按位异或(相同为0,不同为1)

~——按位取反(把0变1,把1变0)

注重讲解前面三个。

注意:它们的操作数必须是整数。 

1.按位与(&):

规则:(有0为0,全1为1)

 请看代码:

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

 我们对补码进行&(按位与)操作。

规则:有0为0,全1为1。

最后得到c的补码00000000000000000000000000000101,此时还是补码形式要转换为原码,又因为正整数的原反补相同,得到c的原码是00000000000000000000000000000101,翻译为十进制并打印在屏幕上为5。

2.按位或(|):

规则:(有1为1,全0为0)

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

步骤和上面差不多

 最终得到的c的补码11111111111111111111111111111101(负整数的补码),要得到原码,将补码取反加1,得到c的原码10000000000000000000000000000011原码,翻译为十进制并打印在屏幕上为-3。

 3.按位异或(^):

规则:(相同为0,不同为1)

 我们可以用(^)交换两个整数,并且不需要用到第三个变量。代码如下:

#include<stdio.h>
int main()
{
    int a = -3, b = 5;
    printf("交换前:a=%d,b=%d\n", a, b);
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;
    printf("交换后:a=%d,b=%d", a, b);
    return 0;
}

 如果有一个数x,x^x=00^x=x

 x ^ 0 = x


x ^ x = 0

解读代码:a=a^b。

b=a^b,这里a的值已经变为a^b,带入后算式为b=a^b ^b,因为b^b=0,又因为a^0为a,所以b=a(赋值成功

然后a=a^b,这里的a和b的值都已改变,带入改变后的值算式为a=a^b ^a,因为a^a=0,又因为0^b=b,所以a=b(交换值成功

4.练习:

(1)用代码实现:求一个整数存储在内存中二进制中的1的个数:

提示:首先,我们可以用右移操作符,每次都只移动1为,每移动1位,我们都对最低位进行检查,也就是看是1还是0,若是1,计数器累加,我们共移动31次(共32位),这样就可以在最低位检查到32位的数值。问题是如何检查呢?这里就可以用到&按位与操作符,把每次移动后的结果&1,就可以检查最低位的数值,最低位为1,按位与后结果为1,最低位为0,按位与后结果为0。

#include<stdio.h>
int main()
{
    int i = 0, n = 0, count = 0;
    printf("请输入你要计算的数字:");
    scanf("%d", &n);
    for (i = 0; i < 32; i++)
    {
        if ((n >> i) & 1 == 1)
        {
            count++;
        }
    }
    printf("一共有%d个1", count);
    return 0;
}

3. 逗号表达式:

(表达式1,表达式2,表达式3,表达式4)

逗号表达式:用逗号隔开的多个表达式。

从左到右依次执行,整个表达式的结果是最后一个表达式的结果。

int a=1;
int b=2;
int c=(a>b,a=b+10,a,b=a+1);

 请问c的值是多少?可知(a>b,a=b+10,a,b=a+1)是一个逗号表达式,逗号表达式规则:从左到右依次执行,结果是最后一个表达式的结果。推出c为13。

 4.表达式求值:

1.整形提升:

整形提升是c语言中的一项规定:在表达式计算时,各种整形首先要提升为int类型,以保持数值的一致性和精度,如果int不足以表示则要提升为unsigned int类型,然后执行表达式计算。

整型提升的意义:
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。
通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。

char a=-1;

char b=1;

char c=a+b;

首先,b和c的值被提升为普通整形,然后再执行加法运算。

加法运算完成之后,结果被截断,然后储存于a中。

1.有符号整形提升,高位补符号位。

负数的整形提升:

char a=-1;(char型为8个比特位)

-1在a中二进制储存为:11111111

因为char是有符号char,整形提升的时候,最高位补充符号位

为:

11111111111111111111111111111111(32位)

正数的整形提升:

char b=1;

1在b中二进制储存为:00000001

因为char是有符号char,整形提升的时候,最高位补充符号位

为:

00000000000000000000000000000001(32位)

2.无符号整形提升:高位补0

2.算术转换: 

如果某个操作符的各个操作数属于不同类型,那么除非其中一个操作数转换为另一个操作数的类型,否则操作就无法进行,下面层次体系称为寻常算数转换

1.long double;

2.double

3.float

4.unsigned long int 

5.long int 

6.unsigned int

7.int

 比如一个double类型的数据+int类型的数据,因为如上图,因为int类型在double类型下面,所以要进行+运算,就要将int转换为double才能进行。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值