整型数据在内存中的存储

一、C语言整型数据类型

(一)整型数据类型

 char       //字符型
 short      //短整型
 int     	//整形
 long    	//长整型
 long long	//更长整型
 float      //单精度浮点型
 double     //双精度浮点型
 //这些是C语言提供整型类型或内置数据类型

(二)内置类型分类

1. 整型家族

char

unsigned char
signed char

short

unsigned short
signed short

int

unsigned int
signed int

long

unsigend long
signed long

2. 浮点型家族

float
double
long double

二、整型在内存中的存储

1、原码、反码、补码

在定义一个整型变量时,需要向内存中申请一块内存空间存放数据,内存空间的大小根据数据类型来决定。

列:

int main()
{
	int a = 10;
	//向内存申请4个字节
	return 0;
}
那么整型是在内存是如何存储?
  • 在内存中整形的存放形式是以二进制的形式来表示,有三种表示形式:原码、反码、补码;
int a = 10;
//00000000  00000000  00000000  00001010
  • 整型有正整形和负整形,其中二进制最高的一位是符号位,表示0表示正数,1表示负数;
    在这里插入图片描述

  • 正整形的原码、反码、补码相同,负整形原码、反码、补码需要计算:

原码:将整型变量正负直接转换成二进制。
反码:符号位不变,则其它位按位取反。
补码:反码最低的一位加一得到补码

int main()
{
	int a = -1;
	//10000000  00000000  00000000  00000001  原码
	//11111111  11111111  11111111  11111110  反码
	//11111111  11111111  11111111  11111111  补码
	return 0;
}

为什么整型在内存中存储是以补码的形式存储?

1、主要解决整型相互加减的问题;
2、不能用原码直接计算,原因是原码计算的结果错误,也会导致符号位溢出的问题;
3、整型统一用补码的形式来存储,方便将符号位和数值域统一处理;
4、CPU中只有加法器,方便将加法和减法统一处理;
5、补码与原码相互转换、运算过程是相同的,不需要额外的硬件电路;

int main()
{
	int a = 10;
	//00000000 00000000 00000000 00001010 //正数的原、反、补相同
	int b = -10;
	//10000000 00000000 00000000 00001010 //原码
	//11111111 11111111 11111111 11110101 //反码(符号位不变,其它位按位取反-->反码)
	//11111111 11111111 11111111 11110110 //补码(反码加一)
    
    //问如何将补码转换成原码?
    //11111111 11111111 11111111 11110110 补码(补码 - 1,得到反码)
    //11111111 11111111 11111111 11110101 反码(符号位不变,其它位按位取反-->反码)
    //10000000 00000000 00000000 00001010 原码
	int c = a + b;
	//00000000 00000000 00000000 00001010  补码(10)
	//11111111 11111111 11111111 11110111  补码(-10)
	//00000000 00000000 00000000 00000001  补码
    //(二进制运算是逢二进一)
	//00000000 00000000 00000000 00000001 
	//00000000 00000000 00000000 00000000
	//00000000 00000000 00000000 00000000    (0) 
	return 0;
}

在这里插入图片描述

2、数据类型在内存存储的顺序

在这里插入图片描述
为什么数据在内存中是倒着存放?
存放数据类型顺序采用大、小端字节序存储模式;

1、为什么会有大端和小端?
  • 计算机系统中,以字节为单位;
  • 地址单元在32位平台上是4个字节,64位平台是8个字节;
  • C语言中有char(8bit)、short(16bit)等(具体看编译器);
  • 对于位数大于 8位的处理器、如16、32、64位处理器,由于寄存器的宽度大于一个字节,就存在着一个如何将多个字节安排的问题,直接导致大端存储模式和小端存储模式。

2、大端存储模式和小端存储模式

  • 以字节为单位存储顺序

大端存储模式

将一个数据低位存放在内存中高地址,数据的高位存放在内存中低地址;

小端存储模式

将一个数据高位存放在内存中高地址,数据的低位存放在内存中低地址;

列如:

int a = 0x00112233;

画图:
在这里插入图片描述

练习:写一个程序判读是小端模式还是大端模式。

  • 思路

存放数据类型是整型类型,而一个整数类型大小是4个字节;
在32 位平台上一个内存单元是4个字节(32bit);
使用char* 解引用1个字节,等于0大端,等于1小端;

#include <stdio.h>

int main()
{
	int a = 1;
	char* pa = (char*)&a;
	if (*pa == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;
}

三、整型提升

整型提升指较小的数据类型转换为通用cpu标准长度数据类型之间相互转换的过程。 如从 char 到 int、short 到 int。整形提升是为了避免在运算过程中出现数据溢出和精度误差等问题。

整型提升的意义

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

总结:

  • CPU只能处理CPU内部固定的长度进行运算(int或unsigned int)。
  • CPU无法直接实现两个不同长度字节的相加运算,需要先将它们转换为相同长度的整型值才能进行运算。如:char与int 需要转换为int类型计算。

1、有符号

整型提升是按变量的数据类型的符号位来提升;
二进制(补码)最高的一位为1时会在高位填充1,为0时会在高位填充0;

#include <stdio.h>

int main()
{
	char a = 4;
	//00000000 00000000 00000000 00000100  补码
	//00000100 (截断)
	char b = 126;
	//00000000 00000000 00000000 01111110  补码
	//01111110 (截断)
	char c = a + b;
	//参与运算,进行整型提升
	//00000000 00000000 00000000 00000100   补码
	//00000000 00000000 00000000 01111110   补码
	//00000000 00000000 00000000 10000010   补码
	
	//00000000 00000000 00000000 10000010   补码
	//10000010 (截断)
	//进行整型提升,符合位是1补1,符合位是0补0
	//11111111 11111111 11111111 10000010 补码
	//11111111 11111111 11111111 10000001 反码
	//10000000 00000000 00000000 01111110 原码

	printf("%d\n", c);
	//-126
	return 0;
}

2、无符号

无符号位指数据类型的二进制序列号全部是有效位无符号位;
无符号位整型提升是直接补0;

#include <stdio.h>

int main()
{
	unsigned char a = 4;
	//00000000 00000000 00000000 00000100 补码
	//00001010 (截断)
	unsigned char b = -127;
	//10000000 00000000 00000000 01111111 补码
	//01111111(截断)   
	unsigned char c = a + b;
	//进行整型提升
	//00000000 00000000 00000000 00000100 补码
	//00000000 00000000 00000000 01111111 补码
	//00000000 00000000 00000000 10000011 补码
	//10000011 (截断)
	//00000000 00000000 00000000 10000011 按照unsigned(无符号)进行整型提升
	//无符号整型提升直接补0
	printf("%u\n", c);
	//%u 打印无符号
	//%d 打印十进制
	return 0;
}

3、有符号、无符号的区别

  • 只有整型家族有所谓的有符合和无符号之分,而是的,浮点型数据没有符号位;
  • 对signed(无符号) int 和 int 是一样的;
#include <stdio.h>
int main()
{
	signed int a = 10;
	int b = 10;
	printf("%d\n", a);
	printf("%d\n", b);
	return 0;
}

在这里插入图片描述

(1)char类型为啥能规划到整型家族里面?

在计算机中,一个字符如%可以表示一个整型数字37,就是ASCII码;

#include <stdio.h>

int main()
{
	int a = 37;
	printf("%c\n", a);  //以字符型打印整型时,也会发生截断
	//%c 打印单个字符
	return 0;
}

在这里插入图片描述

在这里插入图片描述

(2)signed char 和 unsigned char
  • C语言没有明确规定char 是signed char 还是 unsigned char,具体看编译器;
  • 以vs为例,char 是 signed char, 取值范围是 -128 ~ 127,而unsigned char 是0 ~ 255;
    如图:
    signed char
    在这里插入图片描述
    unsigned char
    在这里插入图片描述

列:

#include <stdio.h>

int main()
{
	signed char a = 10;
	//00000000 00000000 00000000 00001010
	//00001010(截断)
	unsigned char b = -128;
	//10000000 00000000 00000000 01111111
	//01111111(截断)
	unsigned int c = a - b;
	//00000000 00000000 00000000 00001010
	//00000000 00000000 00000000 01111111 无符号直接补0
	//00000000 00000000 00000000 11110101 
	//11110101(截断)
	//参与运算的数据类型不同,会发生隐式类型转换。
	//这而是char 类型会进行整型提升将其转换成int类型,然后与int类型的进行运算。
	
	//11111111 11111111 11111111 11110101  整型提升,又是unsigned int全部有效位,结果是一个非常大的整数

	printf("%u\n", c);
	return 0;
}

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值