C语言是贴着计算机运行的一种语言
相对于其他语言我们更需要了解C语言中不同的数据都是怎么存储的。
深度剖析的话 可将其分为四个方向
1. 数据类型介绍
2. 整形在内存中的存储:原码、反码、补码
3. 大小端字节序介绍及判断
4. 浮点型在内存中的存储解析
我们从第一个开始来逐个进行解读
1. 数据类型介绍
基本数据类型介绍
char //字符数据类型
short //短整型
int //整形
long //长整型
long long //更长的整形
float //单精度浮点数
double //双精度浮点数
对数据类型的进行一个基本归类 我们可以将其分为以下五组
整形家族:
浮点数家族:
构造类型:
指针类型
空类型:
void 表示空类型(无类型)
通常应用于函数的返回类型、函数的参数、指针类型。
2. 整形在内存中的存储
我们知道变量的创建是要在内存中开辟空间的。空间的大小是根据不同的类型而决定的。
我们要知道这些空间计算即是如何开辟的?计算机又是如何将数据存储起来的?
我么先来了解这几个概念
计算机中的有符号数有三种表示方法,即原码、反码和补码。
三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位
三种表示方法各不相同。
原码
直接将二进制按照正负数的形式翻译成二进制就可以。
反码
将原码的符号位不变,其他位依次按位取反就可以得到了。
补码 反码加1就能得到原码的补码
正数的原、反、补码都相同。
对于整形来说:数据存放内存中其实存放的是补码。
为什么呢?
在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理; 同 时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需 要额外的硬件电路。
3.大小端介绍
什么大端小端:
大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;(高位存低位 )
小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地址中。(高位存高位)
一道判断大小端的题目
#include <stdio.h>
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;
}
//代码2
int check_sys()
{
union
{
int i;
char c;
}un;
un.i = 1;
return un.c;
}
这道判断大小端的题目巧妙地运用了C语言的隐式类型转换是字节的截断和提升 从计算即大小端存储差异入手 从而巧妙地进行解答
4.浮点型在内存中的存储
我们曾经学习过的浮点数包括: float、double、long double 类型。
但是浮点数与整形在计算机中的存储却大不相同
我们来看一段代码
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;
}
运行结果如图
解读:
根据国际标准IEEE 754,任意一个二进制浮点数V可以表示成下面的形式: (-1)^S * M * 2^E (-1)^s表示符号位,当s=0,V为正数;当s=1,V为负数。 M表示有效数字,大于等于1,小于2。 2^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。
因此对于计算机来说也得按照这种方法进行存储
对于32位的浮点数,最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M。
对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。
特别规定.
1≤M<2
M可以写成 1.xxxxxx 的形 式,其中xxxxxx表示小数部分。
IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。
指数E
首先,E为一个无符号整数 所以IEEE 754规定,存入内存时E的真 实值必须再加上一个中间数,对于8位的E,这个中间数是127
我们经过简单了解现在再对上面的题进行一个合理的解释
对于前两个printf 首先
int n=9;
然后我们将n的地址取出来存入了一个指针变量中
我们知道 地址在内存中一般是占四个字节的 int的变量在内存中也是占四个字节进行存储的
注意
float*是一个浮点型的指针
int位整型变量
我们将整形取地址然后强转成一个float的地址进行存储 显然当我们进行读取时候 会出现错误
n=9的二进制 00000000 00000000 00000000 00001001
当转成float时 因为 float数据分三部分进行存储
对于 00000000 00000000 00000000 00001001 将该数据看作浮点数的话 是一个很小的数据 (-1)^0 * 10 ^0 *1.0000000…… 此处省略
因此打印出来的结果就是一个0.000000 (float数据打印时小数点后跟默认六位)
然后对后面两个printf进行分析
我们在打印前首先对pfloat的值进行了一个改变 --9.0
因此 n的地址的值就发生了改变 同样的pfloat的值也发生了改变
*pfloat打印出来的值是9.000000 很容易理解
n的值打印出来是一个奇怪的数字
9 的二进制表示 00000000 00000000 00000000 00001001
按照上述规则
9.0内存中存储 0 10000010 001 0000 00000000 00000000
我们将其转化为十进制发现正好是
1091567616