整形提升和截断

本文深入探讨了C语言中整型提升和截断的概念。通过实例分析,解释了不同数据类型在运算和赋值过程中如何发生提升和截断,以及这些操作如何影响最终的数值表示。文章强调了有符号和无符号类型在提升过程中的差异,并展示了%d和%u格式符在输出时的影响。此外,还讨论了死循环和字符串长度计算等特殊情况,揭示了底层运算的重要性。
摘要由CSDN通过智能技术生成

整型提升

表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int类型字节的长度,同时也是CPU的通用寄存器的长度。
因此,即使两个char类型的相加,在CPU执行时实际上也要先转化为CPU内整型操作数的标准长度。

通用CPU(general - purpose CPU) 是难以直接实现两个8比特字节直接相加的(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int类型长度的整型值,都必须先转化为int型或者unsigned int ,然后才能送入CPU去执行运算。

  1. 二进制表示的有: 原码,反码,补码;
    存储到内存的为补码:
    打印到屏幕上的为源码:

  2. signed char (有符号的字符型) -128 - 127
    unsigned char (无符号的字符型) 0 - 255

    short 占 2个字节 -32768,32767

如何进行整型提升?

#include<stdio.h>
int main()
{
	char a = 3;
	// 00000011
	// 整型提升后 00000000 00000000 00000000 00000011
	char b = 127;
	// 01111111
	// 整型提升后 00000000 00000000 00000000 01111111
	char c = a + b;
	// 相加后可得 00000000 00000000 00000000 10000010
	// 由于c 是char 类型的所以只能存储一个字节,即在c中存储的为 10000010
	// 因为要在要打印整型,所以10000010要整型提升
	//提升后的结果11111111 11111111 11111111 10000010---为补码
	// 化为原码为 10000000 00000000 00000000 01111110
	printf("%d",c); //因此可得 -126
	return 0;
}
#include<stdio.h>
int main()
{
	char a = 0xb6;
	
	char d = 0x78;// 十进制数为120
	
	//0xb6 = 182 超过了 char 范围
	short b = 0xb600;
	//0xb600 = 46592 远远超过了 short的范围
	// 当超过范围的大小的时候整型提升也就不会等于那个数了
	int c = 0xb600000;
	if(a == 0xb6)
		printf("a");
	if(b == 0xb600)
		printf("b");
		if(c == 0xb600000)
		printf("c\n");//------打印c

	if(d == 0x78)
	printf("d");// -----打印d
	return 0;
}

整型截断

当把一个整数存入char或者short类型的变量时,会发生截断,char取1个字节,short取两个字节。
接下来看了几个例子:

1.

#include<stdio.h>
int main()
{
    char a = -1;
    signed char b = -1;
    unsigned char c = -1;
    printf("a=%d,b=%d,c=%d", a, b, c);//a = -1,b = -1, c = 255 
    return 0;
}
  1. a是一个char类型的变量,-1是一个整型常量,把-1赋值给a时,会发生截断。-1在内存中的补码为11111111 11111111 11111111 11111111,截取低八位11111111赋值给a,此时变量a中存储的补码为11111111。
    当以%d的形式打印变量a的时候,会发生整型提升。由于a是signed(即有符号)类型,==因此向前补最高位符号位的数字1,提升后的补码为11111111 11111111 11111111 11111111。由于%d是有符号的,因此最高位解读为符号位,结果就是-1。
  1. b是signed char类型的,原理同a。
  1. c是一个unsigned char类型的变量,-1是一个整型常量,把-1赋值给c时,会发生截断。-1在内存中的补码为11111111 11111111 11111111 11111111,截取低八位11111111赋值给c,此时变量c中存储的补码为11111111。
    当以%d的形式打印变量c的时候,会发生整型提升。由于c是unsigned(即无符号)类型,因此向前补数字0,提升后的补码为00000000 00000000 00000000 11111111。由于%d是有符号的,因此最高位为解读为符号位,结果就是255

2.

#include <stdio.h>

int main()
{
  char a = -128;
  char b = 128;
  printf("%u\n", a);  // ----4294967168
  printf("%u\n", b);  // ----4294967168
  return 0;
}

128和 -128都是整型常量,赋值给char类型的变量时会发生截断,128的补码为0000000 00000000 00000000 10000000,-128的补码为11111111 11111111 11111111 10000000,截断后a,b内存储的都为10000000。
a,b以%u打印的时候会发生整型提升,由于a,b都是有符号的char类型,因此向前补最高位符号位1,提升后的补码为11111111 11111111 11111111 10000000。由于%u打印的是无符号整型,此时最高位被视作数值位,因此原码与补码相同,该原码转化成十进制就是4294967168。

3.

#include<stdio.h>
int main()
{
    unsigned int i = 0;
    for (i = 9; i >= 0; i--) 
    {
        printf("%u\n", i); 
    }
    return 0;
}

运行图

结果死循环 —>原因如下:当i==0进入的时候,打印0,然后i–,i看似变成了-1,此时内存中存储的补码为11111111 11111111 11111111 11111111。但由于i是一个unsigned int类型的变量,因此最高位应当看作数值位,此时原码和补码相同,而该原码代表的数值为4294967295,因此i会从4294967295开始进入循环,而当i为0的时候,又会重复上述过程,导致死循环的产生。

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[1000] = { 0 };
	int i = 0;
	for(i = 0;i < 1000;i++)
	{
		arr[i] = -1 - i;
	}
	printf("%d",strlen(arr));//255
	return 0;
}

有符号的char类型有下面的运算图, - 128 ~ 127
signed char

	由程序可得arr[]数组里的元素为下:
	arr[i]= {-1,-2,-3,...... -128,127,126,....2,1,0......}
	可得在arr[i] = 0的时候即ASCII码值为即为‘\0’,此时strlen停止计算字符长度。
#include<stdio.h>
unsigned char i = 0;
int main()
{
	for(i = 0;i <= 255;i++),
	{
		printf("Hello world\n");// hello world 死循环
	}
	return 0;
}
	和上面的题目一样,unsigned char 范围是0 ~ 255,当i = 0的时候,i++,二进制为:
	1 00000000 00000000 00000000 00000000,截取后仍为0,将陷入死循环。

总结

整型提升可以分两部分来理解(以char类型为例):
1、看该char类型的变量是signed还是unsigned类型。signed类型在整型提升时向前补最高位符号位,unsigned类型在整型提升时向前补0。
2、看是以%d形式还是以%u形式输出。%d形式代表以有符号视角来解读,因此最高位视为符号位,%u形式代表以无符号视角来解读,因此最高位视为数值位

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值