c语言——整数和浮点数在内存中的存储(图解)

前言:

整数的二进制表达方式有三种:原码、反码、补码。
有符号整数的三种表示方法均有符号位和数值位两部分,2进制序列中,最高位的1位是被当做符号位,剩余的都是数值位。符号位都是⽤0表示“正”,⽤1表示“负”。
原码:直接将数值按照正负数的形式翻译成⼆进制得到的就是原码。 反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。
补码:反码+1就得到补码 反码得到原码也是可以使用:取反,+1的操作。

一、 整数在内存中的存储 。

1. 无符号整数表达方式

无符号数的原码、反码、补码都是相同的。
下面的例子可以具体的解释原码反码补码:

#include <stdio.h>
int main()
{
	int a = 10;
	//10
	//原码:它的二进制序列是1010,因为它是无符号数,符号位是0,所以原码的最前面是0,其余位置也补0
	// 00000000 00000000 00000000 00001010 -原码
	// 00000000 00000000 00000000 00001010 -反码
	// 00000000 00000000 00000000 00001010 -补码
	return 0;
}
//在内存中是由16进制的方式存储的:
//a   2转16进制  —— 0x00 00 00 0A

2. 有符号整数表达方式

正数:原码、反码、补码都是相同的——原码:根据二进制序列得到
负数:原码——根据二进制序列得到,反码:原码取反,补码:反码+1
举例:

#include <stdio.h>
int main()
{
	int b = -20;
	//-20
	// 原码:它的二进制序列是10100,因为它是负数,符号位是1,所以原码的最前面是1,其余位置补0
	//10000000 00000000 00000000 00010100 - 原码
	//11111111 11111111 11111111 11101011 - 反码
	//11111111 11111111 11111111 11101100 - 补码
	return 0;
}
//b在内存中是0xFF FF FF EC

3. 字节序

什么是字节序:字节序就是大于一个字节类型的数据在内存中的存放顺序。是在跨平台和网络编程中,时常要考虑的问题。
字节序经常被分为两类:

  1. Big-Endian(大端):高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。

  2. Little-Endian(小端):低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。

大家可以判断一下自己的电脑是小端还是大端存储:

#include <stdio.h>
int check_sys()
{
	union
	{
		int i;
		char c;
	}un;
	un.i = 1;
	return un.c;
}
int main()
{
	int ret = check_sys();
	if (ret == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;
}

在这里插入图片描述

二、 整型截断,整型提升,算数转换

1. 整型截断

什么是整型截断?就是太长了放不下:

是将占用字节数较多的变量赋值给占用字节数较少的变量时,如将int(4个字节)赋值给char(1个字节)时,这时候int类型的比特位,只将最低的8位赋给了char类型的变量,而高位比特位全部被“截断”;

char a = -1;
//-1默认为整型
//原码——00000000 00000000 00000000 00000001
//反码——11111111 11111111 11111111 11111110
//补码——11111111 11111111 11111111 11111111
//在原数据末尾开始直接按照所需数据大小拿走所需数据:最终得到——111111111

2. 整型提升

什么是整型提升?

首先,我们应该知道这一点:C语言中整型运算总是至少以缺省整型类型的精度来进行的。

这句话什么意思呢?用大白话说就是:C语言中字节数少于整型字节数的数据类型在进行整型运算时,该类型的数据会被默认转为整型数据。

其中,该类型的数据被转化为整型数据的过程就称为整型提升。

为什么会发生整型提升呢?这是由计算机体系结构决定的,我们都知道计算机中的计算都由CPU完成,具体来说是由CPU中的运算器(ALU)完成的。而ALU一般在被设计时,其操作对象——操作数的字节大小被要求至少是int的字节数。此时,我们还要明晰一个事情,那就是数据在被运算时,数据并不是直接在ALU上存储的,而是存储在CPU的寄存器(register)中,而通用寄存器的字节大小与ALU操作数的字节大小保持一致。

其实呢,这个问题和门牌号问题有点相似,比如我一个房子有4个房间,你如果住不满4个房间,那我应该给你安排在哪个小房间呢?我如果随便给你安排一个小房间给你住,我要找你时又要从大房间里找4个小房间才能找到你,这样我的效率就低了,所以,当你要入住时,我会让你变成能住满4个房间时才把你放进去,以方便我用大房间号就能找到你。

其实呢,只有两个数据类型需要整型提升,这两个数据就是char和short。
如果大于4个字节的数据类型呢?那就安排两个房间房间给你住嘛。C语言非自定义数据类型的字节数只有4种(1,2,4,8)。

我举几个例子,大家就清楚了:

char a = 1;
//只有一个字节,就是8个比特位(0000 0001)
//没有定义unsigned char,他就是有符号char
//进行整型提升时,跟我上面讲过的部分一样的,符号位为0,进行整数提升就补0
//0000 0000 0000 0000 0000 0000 0000 0001

char a = -1;
//因为char只有一个字节,所以只有8个比特位(1111 1111)
//没有定义unsigned char,他就是有符号char
//所以他的符号位就为1,进行整型提升时,补三个字节的1
//1111 1111 1111 1111 1111 1111 1111 1111
unsigned short a = -1;
//因为时short类型,所以有两个字节,16个比特位(1111 1111 1111 1111)
//因为是无符号short,所以在进行整型提升时,我只补0就行
//即 —— 0000 0000 0000 0000 1111 1111 1111 1111

3. 算数转换

什么时算数转换:
已知:char 和 short 这两种字节长度小于 int 类型参与算术运算时,会进行整型提升。

而当字节长度大于 int 类型的数据参与运算时,如果某个操作符的两个操作数是不同类型,其中一个操作数需要按级别(级别低的数据转换为级别高的数据)转换为另一个操作数的类型,这样的转换即为算数转换

算数转换的数据级别(由高到低):

long double

double

long float

float

unsigned long int

long int

unsigned int

int

三、 浮点数在内存中的存储

1.浮点数的存储规则

根据国际标准IEEE(电气和电子工程协会) 754,任意⼀个⼆进制浮点数V可以表⽰成下⾯的形式:
V = (−1) ∗ S M ∗ 2E
1.(−1)S 表⽰符号位,当S=0,V为正数;当S=1,V为负数
2.M 表示有效数字,M是大于等于1,小于2的
3.E 表示指数位

举例来说:
⼗进制的5.0,写成⼆进制是 101.0 ,相当于 1.01×2^2 。
那么,按照上⾯V的格式,可以得出S=0,M=1.01,E=2。
⼗进制的-5.0,写成⼆进制是 -101.0 ,相当于 -1.01×2^2 。那么,S=1,M=1.01,E=2。
在这里插入图片描述

2.M的定义

前⾯说过, 1≤M<2 ,也就是说,M可以写成 1.xxxxxx 的形式,其中 xxxxxx 表示小数部分。
IEEE 754 规定,在计算机内部保存M时,默认这个数的第⼀位总是1,因此可以被舍去,只保存后⾯的xxxxxx部分。⽐如保存1.01的时候,只保存01,等到读取的时候,再把第⼀位的1加上去。这样做的目的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第⼀位的1舍去以后,等于可以保存24位有效数字。

3.E的定义

首先,E为⼀个⽆符号整数(unsigned int)
这意味着,如果E为8位,它的取值范围为0255;如果E为11位,它的取值范围为02047。但是,我
们知道,科学计数法中的E是可以出现负数的,所以IEEE 754规定,存⼊内存时E的真实值必须再加上⼀个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。比如,2^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001。

指数E从内存中取出还可以分成三种情况:
1.E不全为0或者不全为1

M:前面加上1.
E:减去中间值

2.E全为0

M:前面加上0.
E:等于1-127(或者1-1023)
为了表示±0,或者接近于0的很小的数字。

3.E全为1

M:前面加上1.
E:减去中间值
如果M全为0,那么表示±无穷大

希望这篇博客对你有所帮助!!!
在这里插入图片描述

  • 47
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值