欢迎━(*`∀´*)ノ亻!,这里是王_哈_哈 Jw~!!!笑一笑呐!!!
目录
下面是关于这篇博客分享的内容提要 :
一.关于数据类型
1.数据类型的基本归类
(char类型本质上是以它的Ascall码值存储的,所以归类到整型。)
2.通过sizeof查看各种类型的所占的空间(单位为字节)
C语言中没有明确规定long的大小,但sizeof(long)一定大于等于sizeof(int)
char占1Byte,8bit!int占4Byte,32bit!float占4Byte,32bit!
二.整型在内存中的存储
整数在内存中存的是它的补码
1.原码反码补码
原码反码补码是整数的三种表示方法,它们的第一位为符号位(0表示正,1表示负),其余为数值位。原码就是将该整数按正负数的形式直接翻译成二进制。
正数的原反补码相同。
负数的反码:符号位不变,其余位按位取反;补码:反码+1;
例如:
10
原码:0000 0000 0000 0000 0000 0000 0000 1010
反码:0000 0000 0000 0000 0000 0000 0000 1010
补码:0000 0000 0000 0000 0000 0000 0000 1010
-10
原码:1000 0000 0000 0000 0000 0000 0000 1010
反码:1111 1111 1111 1111 1111 1111 1111 1111 0101(符号位不变,其余位按位取反)
补码:1111 1111 1111 1111 1111 1111 1111 1111 0110(反码+1)
所以当我们在运行
int main()
{
int a = 10;
int b = -10;
return 0;
}
这样一段代码时,计算机在内存中就开辟了两个4字节的空间分别存放a和b的补码。
(实际上当我们在编译器上进行调试查看内存时为了方便展示,显示的是十六进制的数值)所以理论上当我们查看内存时应该是这样的:
但实际上当我们打开vs,输入这段代码,在进入F10调试后,点击调试-->窗口-->内存 分别输入了&a,&b,并将列数改为4看到的结果是:
发现每个字节的顺序与我的理论正好颠倒,这是由于计算机的大小端字节序存储的原理。
2.大小端字节序存储
什么是大小端字节序存储?
字节序:以字节为单位的存储顺序。(C语言的数据存储是以字节为单位的,每个地址单元对应一个字节即8bit)。
大端存储模式:数据的低位保存在内存的高地址;
小端存储模式:数据的高位保存的内存的低地址。
(对于一个32bit的十六进制数0x11223344来说,11是高位,44是低位)
如何判断当前机器的字节序?
(我们常用的x86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式,有些ARM处理器还可以用硬件来选择是小端还是大端)
方法一(用强制类型转化取出一个字节判断)
(我们可以用一个程序实现判断:我们创建一个int类型的i,放入一个1,把他转化为正常的十六进制就是0x 00 00 00 01,内存中一个字节一个字节地存储,如果是大端:0x 00 00 00 01,小端:0x 01 00 00 00. 接着我们把本来为int*类型的&i强制类型转化为char*并解引用的值返回,如果是大端就是ox00=0,小端即为0x01=1)
int check_sys()
{
int i = 1;
return(*(char*) & i); //将&i强制类型转化为char*
}
int main()
{
int ret = check_sys();
if (ret == 1)
printf("小端\n");
else
printf("大端\n");
return 0;
}
方法二(使用联合体):
(因为联合体内的数据占的是一块内存,下面这个联合体的内存大小为4个字节,c正好在低字节处,如果是小端存储01和char占同一块内存就会返回1,反之和上面原理一样。)
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;
}
三.浮点型在内存中的存储
我们常见的浮点数有3.14,1E10(1.0*10^10)等,常见类型有float,double,long double。它们的表示范围在float.h中定义。浮点数在计算机中也用二进制形式存储,但和整型大相径庭。
1.一个存储差异的栗子
(这里不是把浮点数和整数相互强制转换,而是将他们分别用对方的存储方式解释并打印)
当我们把整型9用浮点数存储方式解释之后变成了0.000000,而9.0用整型存储方式(补码)解释之后变成了一个很大的数字,就很六。那么浮点数到底是咋子存储的嘞(色.jpg)
2.浮点数的存储规则
存储模型
根据国际标准IEEE(电器和电子工程协会)754,任意一个二进制浮点数V可以表示成下面形式:V=(-1)^S*M*2^E
- (-1)^S表示符号位。S=0时V为正数;S=1时V为负数。
- M表示有效数字,大于等于1,小于2。
- 2^E表示指数位
例如:
- 十进制的5.5写成二进制为101.1 如果用以上方式表示:(-1)^0*1.011*2^2 。此时S=0,M=1.011,E=2
- 十进制的0.5写成二进制为0.1 → (-1)^0*1*2^(-1).此时S=0,M=1,E=-1
对于一个32位的浮点数,它的存储模式如下图(对于一个64位的浮点数E占11bit,M占52bit):
存储细节
S
S存储比较简单,在第一位,正数为0,负数为1.
E
E代表的是指数(二进制的科学计数法,咱可以理解为小数点向哪边移动了多少位,向左移动两位是2,向右移动两位就是-2),实际上是有正有负的,但是E是一个无符号整数(unsigned int)。如果是8位的E,取值范围就是0~255;如果是11位,取值范围0~2047.
为了能够表示正负,IEEE754规定,存入E的真实值必须再加上一个中间数,对于8位的E,这个中间数为127,对于11位的E中间数为1023。比如
5.5的表面E值为2,实际E=2+127=129,即10000001.
0.5的表面E值为-1,实际E=(-1)+127=126,即01111110.
M
因为M大于等于1小于2,就是1.xxxxxxx,。IEEE754规定反正这个个数一直为1,就不保存,只保存xxxxxxx,所以保存5.5(101.1)时,M=1.011,实际上保存的是011(前面20位补0)
例子
从内存中拿出
分三种情况,S表示正负
E不全为0或不全为1
将指数E减去127(或1023),得到真实值,再将有效数字M前加上第一位的1
E全为0
指数E=1-127(或1-1023),得到真实值,有效数字M不再加上第一位的1
(如果E全为0的话,说明原来的指数为-127,说明0.00000(126个0)1,就是一个趋于零的数字,正负取决于S)
E全为1
这时,如果有效数字M全为0,表示正负无穷大
3.解释前面存储差异的栗子
1.用浮点数的存储方式解释整数9
int n = 9;内存中是这样的(以9的补码存储):
00000000000000000000000000001001
float* pf = (float*)&n;(我们给计算机洗脑,说这块内存是以浮点数形式存的,所以)
计算机把它分成SEM三部分,第一个0代表正数,后八个为E都是全为0,直接得出0.000000(%f默认六位小数)
2.用整数的存储方式解读浮点数9.0
float i = 9.0;(根据浮点数的存储规则,内存上是这样的:)
0 10000010 00000000000000000000001
int* pi = (int*)&i;(我们给计算机洗脑这不是以浮点数存储方式存储的,是一个补码,所以)
它是一个正数直接转化为十进制,就是刚刚运行出来的结果
好啦~以上就是这次分享记录的全部内容,真切体验到创作不易了,呜呜呜~我还要还得再改进改进。谢谢支持,谢谢自己~
点个赞赞叭~~