数据在内存中的存储(一个新手的理解)

1.整数在内存中的存储

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

  负整数的三种表示方法各不相同。

提示:负数的反码等于原码符号位不变,其他位置的二进制位取反。

           负数的补码等于反码+1.

  对于整型来说:数据存放在内存中其实存放的是补码。

  为什么呢?

  使⽤补码,可以将符号位和数值域统⼀ 处理;

2.大小端字节序和字节序判断

首先看一个代码(VS系统)

#include 
int main()
{
 int a = 0x11223344;
 
 return 0;
}

 这个代码的结果呢?

数据在内存中的存储(一个新手的理解)_第1张图片

可以看出低位的数字存储在了前面;这是小端存储

2.1什么是大小端?

超过一个字节的数据在内存中存储时,就有存储顺序的问题,按照不同的存储顺序,我们可以把分为大端字节存储和小端字节存储。在不同的编译器中不同。

大端存储:通俗来说就是数字的比较大的位数存到了前面。就像 0x11223344,如果为大端存储的话那在内存里面 先存储的就是 11 22 33 44,和上面的图片相反

小端存储:就是数字的比较小的位数存到了前面。和上图一样!!!

一个自编小口诀,前大大,前小小。就是前面如果是数字位数大的数字的话就是大端存储,反之相同。

2.2为什么有大小端呢?

每个地址单元都 对应着⼀个字节,⼀个字节为8 bit 位,但是在C语⾔中除了8 bit 的 char 之外,还有16 bit 的 short 型,32 bit 的 long 型(要看具体的编译器),另外,对于位数⼤于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度⼤于⼀个字节,那么必然存在着⼀个如何将多个字节安排的问题。因此就导致了⼤端存储模式和⼩端存储模式。

2.3那怎么知道编译器是什么存储呢?

可以写一个小代码来研究

#include 
int check_sys()
{
 int i = 1;
 return (*(char *)&i);
}
int main()
{
 int ret = check_sys();
 if(ret == 1)
 {
 printf("⼩端\n");
 }
 else
 {
 printf("⼤端\n");
 }
 return 0;
}

 这个代码这样看,在最上面的check 函数中先给 int i = 1,之后返回时将 i 的 强制转换为 char * 是因为 本来 存储的是 int 变量 占了4个字节 ,如果把这个 存储的 字节 单独拿出来看呢, 如果 前面 第一个 字节存的 是 01,那就代表了 将小位的数字存在了前面,为小端存储,反之相同。

2.4几个有趣的小练习 

#include 
int main()
{
 char a= -1;
 signed char b=-1;
 unsigned char c=-1;
 printf("a=%d,b=%d,c=%d",a,b,c);
 return 0;
}

输出结果a b = -1,c =255.

这个练习,可以看出用char 来存储数字,但存储数字的时候存的是补码。因为char 其实是signed char的缩写。所以a b 其实是相同的。因为 sighed char 是有符合的字符型,只保存一个字节,所以 3个变量的二进制位都是 11111111.因为前两个变量是有符号的,所以在下面要求打印%d 时发生整型提升,因为两个变量是有符号的,所以提升时前面的符号位为1.所以提升时32个二进制位全为1 。但打印时 是以原码打印,因为前两个变量的符号位是1 是负数。负数的原码 等于 补码减一 并取反。所以最终前两个变量的 原码就是 第一位二进制位和最后一位二进制位为1,其他全为0,所以等于-1.

但不同的是 unsighed char 因为 是无符号整型,在整形提升时,c变量的二进制位前面全部补0.所以c 的二进制表示是 00000000 00000000 00000000 11111111.因为正数的原反补码相同所以,c = 255.

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





#include 
int main()
{
 char a = 128;
 printf("%u\n",a);
 return 0;
}

第一个a 打印出来一个特别大的数字,第二个char

这个练习要求打印 %u 就是无符号整型。给的两个有符号的 char 类型。

第一个 char 因为是负的-128,所以他的 原码其实就是 10000000,对他整型提升后 就是。

11111111 11111111 11111111 10000000,因为要打印无符号整型,所以第一个二进制位不看做符号位。,所以这个数字是正数,原码反码补码相同,所以打印出来一个特别大的数字。

第二个 a 其实写下来和第一个a 的原码其实是一样的,因为 char 只有 一个字节8个二进制位。-128 和 128的二进制位其实相同,所以两个数字的结果相同。

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

数据在内存中的存储(一个新手的理解)_第2张图片 

 这个代码的最终结果是255.

为什么呢?首先给了一个 1000的i 循环。将a【i】 = -1 - i;

因为a 【i】是char 类型 只有 1个字节 8 个二进制位。第一个a【i】 = -1.二进制位是

10000001.每次都减一直到 11111111 ,它的原码就是 10000000.在vs 中这个数字为-128

所以-128再减一 就变成了 127 在一直减到 00000000.其中总共走了 255次。出现 0 。

strlen 计算字符直到出现 0.所以得出255.

 

#include 
unsigned char i = 0;
int main()
{
 for(i = 0;i<=255;i++)
 {
 printf("hello world\n");
 }
 return 0;
}

数据在内存中的存储(一个新手的理解)_第3张图片 

无符号char型的范围如上图。

本题的无符号char 类型 的范围 0 -255.因为for 循环一直打印到255.但255加一 又 等于 0.

这就会导致死循环。

 

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

这题也是一个死循环,因为是无符号整型,所以当减到0时,再减一,就变成了 32个二进制位都是 1.这样一直循环下去。 

3.浮点数在内存中的存储

常⻅的浮点数:3.14159、1E10等,浮点数家族包括: float double long double 类型。
浮点数表⽰的范围:float.h中定义

3.1练习

int main()
{
 int n = 9;
 float *pFloat = (float *)&n;
 printf("n的值为:%d\n",n);
 printf("*pFloat的值为:%f\n",*pFloat);
 *pFloat = 9.0;
 printf("num的值为:%d\n",n);
 printf("*pFloat的值为:%f\n",*pFloat);
return 0;
}

数据在内存中的存储(一个新手的理解)_第4张图片

由上图可以看出浮点数和整型的存储方式是不同的

3.2浮点数的储存 

数据在内存中的存储(一个新手的理解)_第5张图片

上图则是浮点数在计算机内部的表示方法。

⼗进制的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。
对于32位的浮点数,最⾼的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M
对于64位的浮点数,最⾼的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M

3.2.1 浮点数存的过程

M保证是 1<=M<2.

E如果为8位取值范围就是0-255,如果为11位就是0-2047.根据IEEE的规定,需要给E中额外存入一个数字 8位E就是 127 ,11位就是 1023.⽐如,2^10的E是 10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001。

3.2.2浮点数取的过程

指数E从内存中取出还要分为三种情况。

1.E不全为0或1.
这时,浮点数就采⽤下⾯的规则表⽰,即指数E的计算值减去127(或1023),得到真实值,再将有效
数字M前加上第⼀位的1。
⽐如:0.5 的⼆进制形式为0.1,由于规定正数部分必须为1,即将⼩数点右移1位,则为1.0*2^(-1),其
阶码为-1+127(中间值)=126,表⽰为01111110,⽽尾数1.0去掉整数部分为0,补⻬0到23位
E全为0
这时,浮点数的指数E等于1-127(或者1-1023)即为真实值,有效数字M不再加上第⼀位的1,⽽是还
原为0.xxxxxx的⼩数。这样做是为了表⽰±0,以及接近于0的很⼩的数字。
E全为1
这时,如果有效数字M全为0,表⽰±⽆穷⼤(正负取决于符号位s);
好了,关于浮点数的表⽰规则,就说到这⾥。

你可能感兴趣的:(c语言,c语言,开发语言,c++)