我们知道一个变量的创建是要在内存中开辟空间的,空间的大小是根据不同的类型而决定的,而且不同的类型也影响着我们看待内存空间的视角。
比如:int a = 20,float b= 5.0
接下来我们看看数据在所开辟的类型中是如何存储的?
整型在内存中的存储
整型家族
char
unsigned char,signed char
short
unsigned short,signed short
int
unsigned int,signed int
long
unsigned long,signed long
原码、反码、补码
- 原码: 直接将二进制按照正负数的形式翻译成二进制即可
- 反码: 原码的符号位(用0表示正,用1表示负)不变,其他位依次按位取反
- 补码: 反码加1
对整型来说:数据存放内存中其实存放的是补码(正数的原反补码都相同)
原因是:1.符号位和数值位可以统一处理。2.加法和减法可以统一处理(CPU只有加法器)。3.补码与原码相互转换,运算过程也是相同的,不需要额外的硬件电路。
16进制存放
我们发现对a和b分别存放的是补码,但顺序有点不对劲,这又是为什么呢?
大端和小端
-
大端存储模式:数据的低位保存在内存的高地址中,数据的高位保存在内存的低地址中。
-
小端存储模式:数据的地位保存在内存的低地址中,数据的高位保存在内存的高地址中。
内存中从左到右依次是由低地址到高地址
-
设计一个程序来判断当前机器的字节序
#include <stdio.h>
int check()
{
int x = 1;
return (char)x;//强制类型转换,保留最低位的一个字节。
}
int main()
{
int ret = check();
if (ret == 1)
{
printf("小端");
}
else
{
printf("大端");
}
return 0;
}
下面程序输出什么?
练习题1:
#include<stdio.h>
int main()
{
char a = -1;
signed char b = -1;
unsigned char c = -1;
printf("a=%d\nb=%d\nc=%d\n", a, b, c);
return 0;
}
运行结果:
a=-1,b=-1,c=255
解析:
唯一的不同点就是a,b,c 的类型不同,输出结果却有如此大的差异。
将-1(int)2进制为11111111 11111111 11111111 11111111
的值赋给char类型时首先发生的时整型的截断,char接收到的只是-1最低位的一个字节2进制为:1111 1111
。
printf输出时以%d的形式输出cahr类型会发生整型的提升,发生提升时,有符号数高位补符号位,无符号数高位补0。
有符号数a的补码为:11111111 11111111 11111111 11111111
有符号数b补码为:11111111 11111111 11111111 11111111
无符号数c补码为:00000000 00000000 00000000 11111111
练习题2:
#include<stdio.h>
int main()
{
char a = -128;
printf("%u\n", a);
return 0;
}
运行结果:
4294967168
解析:
首先根据a的原码写出a的补码
根据整型的截断,char接收到的是a最低位的一个字节 2进制为:1000 0000
打印时%u为无符号整型,则cahr a发生整型提升 无符号数a的补码为:11111111 11111111 11111111 10000000
无符号数的补码=原码。
练习题3:
#include<stdio.h>
#include<string.h>
int main()
{
char a[1000];
int i;
for (i = 0; i < 1000; i++)
{
a[i] = -1 - i;
}
printf("%d\n", strlen(a));
return 0;
}
运行结果:
255
解析:
strlen求字符串长度,实质找的是’\0’的位置,即a = 0时。
i从0开始到999,a[i]接收值从-1到-1000,char a [i]会发生整型的截断,低位一个字节为 0000 0000
时,即求出字符串长度。(注意‘\0’不计入字符串长度)
i = 0时 -1截断之后为:1111 1111
i = 1时 -2截断之后为:1111 1110
i = 2时 -3截断之后为:1111 1101
当达到 0000 0000
时i = 255(下标),则字符串长度为0到254,输出255。
浮点型在内存中的存储
浮点型家族
float,double,long double
浮点型存储的例子
n和*pFloat在内存中明明是同一个数,为什么整数和浮点数的解读结果会差别这么大?要理解这个结果,我们首先要搞懂浮点数在计算机内部的表示方法。
根据国际标准IEEE(电气和电子工程协会)754,任意一个二进制浮点数v可以表示为下面的形式:(-1)^s*M*2^E
(-1)^s表示符号位,当s=0时,v为正数;当s=1时,v为负数;
M表示有效数字,大于等于1小于2;
2^E表示指数位;
举例来说:
如何把十进制的浮点型转换为二进制呢?
例如十进制0.5转化为二进制为0.1
float a = 5.0存储如下 (-1)^0*1.01*2^2
对于双精度浮点型 S(1bit) E(11bit) M(52bit)
因为整型存储和浮点存储的规则不同,所以在输出时才会产生如此大的差别。
回到刚开始的问题:
整型9: 0000 0000 0000 0000 0000 0000 0000 1001还原为浮点型
由浮点存储规则得 指数E全为0,E=1-127,有效数字M不再加1,而是表示为0.xxxxx,浮点数V=(-1)^0*0.00000000000000000001001*2^-126=1.001*2^-146,所以用十进制小数表示为0.000000
浮点型9.0用二进制表示为1001.0
V=(-1)^0*1.001*2^3,S=0,M=1.001,E=3+127=130,存储为0 10000010 001 0000 0000 0000 0000 0000,还原为10进制为1091567616