整形提升与截断

一、什么是整形提升与截断

  • 整形提升:整型提升是C程序设计语言中的一项规定,通常在表达式计算时,计算机为了方便是进行32个bit位计算,那么对于不够32个bit位的类型就会进行整形提升,然后再执行表达式的运算。
    举个例子:
#include <stdio.h>

int main()
{
	int a = 1;
	char b = 2;
	printf("%d", a + b);
	return 0;
}

a是四个字节的整形,而b是char类型的,只有一个字节。那么在进行a+b的运算的时候就会对b进行整形提升,把b提升到4个字节然后再进行计算。

  • 截断:截断则与整形提升相反,就如字面意思,把一个占用过多比特位的数据给截断。通常发生在把更大类型的值赋予一个较小的类型时。例如把一个int类型的值赋给char类型时,由于int是4个字节,char是一个字节,那么为了把值放入char就会对int类型的值进行截断,把它截断取其中低地址的1个字节。
    为了深入了解整形提升与截断,那么就要了解数据是如何储存到内存之中,然后又是如何从内存之中取出来的,这就要涉及到源码反码以及补码了。

二、什么是源、反、补码

  • 源码:顾名思义,就是直接把数字转换成二进制所对应的数。我们以int类型整形为例,一个整形4个字节,32个bit位。其中第一位我们称为符号位,0表示正,1表示负。
    在这里插入图片描述

  • 反码:这里要分两种情况,如果是正数那么它的源、反、补码都是一样的。但如果是负数,它的补码就是对除符号位之外的进行按位取反。

  • 补码:正数的补码与反码相同,负数的补码就是在反码的基础上加一。
    在这里插入图片描述

三、程序是如何进行整形提升的

1、无符号与有符号的区别

在了解了数据是如何存储在内存之中的之后,我们就可以来研究整形提升是如何进行的了。
通过之前的了解,我们可以知道32个比特位中,第一位是一个符号位,用于表示正负。但也有一种特殊情况,那就是unsigned修饰的类型是无符号的,即第一位不再表示符号位了。例如:

#include <stdio.h>

int main()
{
	unsigned int a = -1;
	printf("%u", a);
	return 0;
}

其中-1是有符号的,在赋值给了unsigned修饰的int型变量a之后,第一位符号位也会被认为是2的31次方了。
在这里插入图片描述
由此可见,符号位的存在与否是极为重要的。同样的,在整形提升中,符号位也是至关重要的而且十分容易搞混的。为了便于理解我们把char分为有符号和无符号两种类型来进行进一步的讨论。

2、char型的整形提升

  • 有符号的char型:对于char它是一个字节的,并且默认定义char的时候它是有符号的类型,也就是第一位是符号位,只有7个比特位来存储数据大小,其中char储存的是ASCII值。而一个char只有一个字节,除开符号位,对应二进制最大只能是1111111,换算成十进制就是127。这也是ASCII值只有0到127的原因。对于有符号的char型在整形提升时,我们会根据他的符号位进行整形提升。如果符号位是1,那么就会在左边补上24个1,反之是0就会补上0。
    在这里插入图片描述

  • 无符号的char型:对于无符号char型来说,在进行整形提升的时候,无论任何时候都是在左边补充0。还是上一个例子,如果对a用unsigned进行修饰,结果就会截然不同。
    在这里插入图片描述
    在这里一定要注意%d是按有符号整形输出的,所以a+b是有符号的,但a是无符号的所以a整形提升是按照无符号的来。在进行了a+b之后就按照有符号的整形来输出。

四、典型例题

在了解了整形提升和截断之后,我们来看看这道题。

int main()
{
  char a[1000] = {0};
  int i=0;
  for(i=0; i<1000; i++)
  {
    a[i] = -1-i;
  }
  printf("%d",strlen(a));
  return 0;
}

大致看了一遍之后我们不难发现输出的就是a这个字符串的长度。strlen函数是会在遇到’\0’的时候停止的,那么我们就要去寻找a中的‘\0’才能知道具体字符串有多长。
首先,char是一个有符号的类型,那么当i等于0的时候,a[0]就是-1。
-1的ASCII值是 10000000 00000000 00000001;
反码是11111111 11111111 11111110;
补码是11111111 11111111 11111111;
截断之后a[0]之中存储的就是11111111;
对应的反码是11111110;
补码为10000001即此刻a[0]中放的是ASCII为-1的值。

当i等于1的时候:
a[1]中的补码就是-1的补码减去1的补码即
11111111 11111111 11111110截断即11111110;
对应的反码是11111101;
补码为10000010即ASCII为-2的值。
不难推断,当i等于126时a[126]中的ASCII值为11111111即-127;

那么当i等于127的时候呢?
首先-1的补码为11111111 11111111 11111111;
127的补码为00000000 00000000 01111111;
-1-127的补码为11111111 11111111 10000000;
截断之后就是10000000;换成源码就是11111110这个换发不能按照一般的方法来理解,在电脑中补码转换成源码其实和源码转换成补码的方式一样的,与我们把补码转换成反码再到源码的结果一样只是步骤不一样。而这里减一就会出问题;10000000转化过程实际就是到11111111再到11111110。
举个例子:
-1的补码为11111111 11111111 11111111;
电脑的转换方式是把它看成源码然后转换为补码,补码就是-1的源码。
转换一次后为10000000 00000000 00000000;(源码到反码的转换方法)
再转换一次就是-1的源码:10000000 00000000 00000001;(反码到补码的转换方法)

之后当i等于128时:
-1的补码为11111111 11111111 11111111;
128的补码为00000000 00000000 10000000;
-1-128的补码为11111111 11111111 01111111;截断后为01111111,对应的ASCII值为127。

同理推断i等于255时ASCII会递减到0即‘\0’。
-1的补码为11111111 11111111 11111111;
255的补码为00000000 00000000 11111111;
-1-255的补码为11111111 11111111 00000000;
截断后为0000000;正确。
当i等于255时表示arr[255]为‘\0’;即第256个数为‘\0’,所以字符串的长度为255。
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值