C语言——数据的存储
数据类型介绍
在C语言中常见的字符类型7种(由小到大列出)
char:(字符型)在内存中占1个字节
short:(短整型)在内存中占2个字节
int:(整型)在内存中占用4个字节
long:(长整型)在内存中占用(long long>=long>=int)个字节,根据编译器决定
long long:(长整型)在内存中占用8个字节
float:(单精度浮点型)在内存中占用4个字节
double:(双精度浮点型)在内存中占用8个字节
这里提一下在使用长整型时一般使用 long long,因为long的字节数是不确定的,所有建议直接使用long long。
数据类型有无符号数(unsigned)和有符号数(signed)只需在创建数值时在类型前面加上,一般只有创建无符号类型时才会加上,普通数都是默认有符号。
数据在内存中的存放
内存中的有符号数有三种二进制的形式:原码,反码,补码。但是在内存中有符号数都是以二进制补码的形式存放,当在内存中存放一个数值时,编译器会自动将数值转换为二进制。三种形态分别由符号位和数值位组成,二进制的第一个数字,**‘1’代表的是负数,‘0’**代表的是正数。
如何转换二进制为补码和如何转换回原码?
一般我们在读一个数字时都是二进制的原码,原码转换成反码(符号位1不变其他位按位取反),反码转换为补码(反码加一)。补码转换为原码有两种方法:1.补码减一,再符号位不变,其他位按位取反。2.补码加一,再符号位不变其他位按位取反。其实原码变成补码和补码变成原码方法一样!
正数在内存中原码,反码,补码相同。
负数在内存中需要转换才可以得到补码。
数据在内存中都是先使用高地址存储再使用低地址,例图:
但是在这里会发现数据的存储似乎很奇怪!这时候就不可避免的会谈到我们的大小端问题。
大小端(存储模式)
小端:数据的低位放在低地址处,数据的高位放在高地址处
大端:数据的高位放在低地址处,数据的低位放在高地址处
可以看见本机的存储方式是小端模式,一般的编译器采用的都是小端模式存储。
那么如何知道自己的编译器使用的是大端还是小端呢?
这里为大家提供一个函数:
#include<stdio.h>
int is_what()
{
int a=1;
return (*(*char)&a);//取出a的地址强制类型转换,然后解引用得到a的最低位地址,返回
}
int main()
{
if(is_what())//如果返回值为真,也就是 1 判断编译器为 小端
{
printf("小端\n");
}
else
printf("大端\n");
return 0;
}
在一般的编译器下都会使用小端存储模式,但是我们应该知道如何去实现这个函数和判断编译器的存储模式。
整型char 的范围
整型char的范围是127~-128,所以当你为整型char赋值时应该格外小心,特别是遇到 unsigned char 时,一不小心可能便会遇见bug。
例如:
#include<stdio.h>
int main()
{
unsign char i=0;
for(i=0;i<=127;i++)
{
printf("hello\n");
}
return 0;
}
看起来好像并没有什么问题,可是当你打印时会出现死循环的现象。
原因就是当i=128时会自动变成-128,条件成立,程序继续,所以应该特别注意当使用char类型时应该避免写出bug。
浮点型在内存中的存储
整型和浮点型,两个相同的数字,16进制却不同:
可知浮点型和整型在内存中是不同的存储方法,所以当你将一个浮点型的强制类型转换的时候,可能会出现意料不到的结果。
那么浮点数是如何存储在内存中呢?
根据相关资料,我找到了这个公式。
(
−
1
)
s
∗
M
∗
2
E
(-1)^s*M*2^E
(−1)s∗M∗2E
s位是用来表示该浮点数的正负,为正数时s=0,负数时s=1。
M是有效数字,大于1 ,小于2
2^E是用来表示指数位
float数据在内存中存储方式图解:double S也是一位,E是11位,M是52位
例如:5.5在内存中存储
先将5变成二进制->101,在将0.5变成二进制->.1,结合起来->101.1->1.011*2^2,得到:E=2,M=1.001,s=0;
根据规定,当E存入内存中时需要+127(double+1023),M存入需要把 1 省略。
得到 5.5的二进制序列->
0100 0000 1011 0000 0000 0000 0000 0000
16进制->
40 b0 0000
不过当E<0 时,编译器会自动判定该数为0,当E为全1时,编辑器默认无穷大,取决于S为正或者负。
今天的分享就到这里,觉得有用的话,可以留下你的赞吗?☺