数据的存储
- 1. 数据类型介绍
- 1.1 类型的基本归类
- 2. 整型在内存中的存储
- 2.1 原码、反码、补码
- 2.2 大小端介绍
- 2.3 练习
- 3. 浮点型在内存中的存储
- 3.1 一个例子
- 3.2 浮点数存储规则
1. 数据类型介绍
基本的内置类型、大小(字节)(VS编译器)
意义:
1. 大小决定了适用范围
2. 提供了看待内存空间的视角。例如:在VS编译器中创建一个整型变量,我们向内存申请了4个字节的空间。
1.1 类型的基本归类
整型家族:
浮点型家族:
构造类型:(自定义类型)
指针类型:
空类型:
void 表示空类型(无类型)
通常应用于函数的返回类型、函数的参数、指针类型。
2. 整型在内存中的存储
我们之前讲过一个变量的创建是要在内存中开辟空间的。空间的大小是根据不同的类型而决定的。
那接下来我们谈谈数据在开辟内存中到底是如何存储的?
比如:
int a = 20;
int b = -10;
我们知道为a 分配四个字节的空间。
那如何存储?
下来了解下面的概念:
2.1 原码、反码、补码
对于整型来说:数据存放内存中其实存放的是补码。
为什么呢?
在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;
同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
//举个例子:
int a = 1;
int b = 1;
int c = a - b;
//1-1
//因为CPU只有加法器,所以可以这样转换。
//1+(-1)
//如果用原码计算的话,
//00000000000000000000000000000001-1
//10000000000000000000000000000001-(-1)
//10000000000000000000000000000010-(-2)
//得到了-2,这样是错误的,用反码的话实在麻烦,所以用补码很方便。
补码转成原码有两种方式:
- 先进行按位取反,再+1便可得到原码
- 先进行-1,再按位取反便可得到原码
我们看看在内存中的存储:
我们可以看到对于a和b分别存储的是补码。但是我们发现顺序有点不对劲。
这又是为什么呢?
往下看!!!
2.2 大小端介绍
例如:
一个16bit的short型x,在内存中的地址位0x0010,x的值为0x1122,那么0x11为高字节,0x22为低字节。
对于大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。
小端模式,刚好相反。
我们常用的X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以有硬件来选择是大端模式还是小端模式。
请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。
思路:以1为例,在大端模式下,01在高地址处,在小端模式下,01在低地址处。所以我们判断低地址处的数是否为01,则可以判断大端字节序和小端字节序。
#include<stdio.h>
int check_sys()
{
int i = 1;
return (*(char*)&i);
//将i的地址强制类型转为char*,再进行解引用得到1个字节内容
}
int main()
{
int ret = check_sys();
if (ret == 1)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
2.3 练习
进行一些练习来巩固知识。
//输出什么?
#include<stdio.h>
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;
}
以上最后的二进制序列是补码,需要转换成原码即是答案!
#include<stdio.h>
{
char a = -128;
printf("%u\n", a);
return 0;
}
//10000000 00000000 00000000 10000000-原码
//11111111 11111111 11111111 01111111-反码
//11111111 11111111 11111111 10000000-补码
//10000000-char a
//00000000 00000000 00000000 10000000-整型提升(%u是十进制的无符号数)。
//11111111 11111111 11111111 10000000-原码
#include<stdio.h>
int main()
{
char a = 128;
printf("%u\n", a);
return 0;
}
//00000000 00000000 00000000 10000000-原码
//01111111 11111111 11111111 01111111-反码
//01111111 11111111 11111111 10000000-补码
//10000000-char a
//和上一道题目一样。
这个图就是解释上面两个题的规律,无符号的char取值范围是0-255
int i = -20;
unsigned int j = 10;
printf("%d\n", i + j);
//i:
//10000000 00000000 00000000 00010100-原码
//11111111 11111111 11111111 11101011-反码
//11111111 11111111 11111111 11101100-补码
//j
//00000000 00000000 00000000 00001010-原码(反码、补码)
//相加后,在进行格式化为有符号的整数
//11111111 11111111 11111111 11110110
//10000000 00000000 00000000 00001010-原码
//答案是-10
unsigned int i;
for (i = 9; i >= 0; i--)
{
printf("%u\n", i);
}
//首先i是无符号的整数;
//然后进行一个循环,打印无符号的数
//既然i是无符号的数,那么i会一直大于等于0,结果就是死循环。
int main()
{
char a[1000];
int i;
for (i = 0; i < 1000; i++)
{
a[i] = -1-i;
}
printf("%d",strlen(a));
return 0;
}
//这个程序存放从-1开始递减的数
//char是有符号的,那么取值范围是-128-127。strlen是遇到\0就停止,0就代表了\0,循环的时候,-1,-2,……,-128,127,……,1,0,此时strlen遇到\0就停止了,所以长度为255。
#include<stdio.h>
unsigned char i = 0;
int main()
{
for (i = 0; i <= 255; i++)
{
printf("hello world\n");
}
return 0;
}
//首先无符号的char类型取值范围是0-255,所以当再一次+1时,就会从头开始
//11111111-255
//100000000-加一后,舍去前面的数
//00000000-0
//结果就是死循环
练习做完了之后,相信对整型在内存中的存储有了很深刻的印象,那么接下来讲浮点型在内存中的存储!
3. 浮点型在内存中的存储
常见的浮点数:
3.14159
1E10,代表1*10^10
浮点数家族包括:float、double、long double类型。
浮点数表示的范围:float.h中定义。(查看整型的范围的话,寻找limits.h文件)我们打开everything软件,搜索float.h,找到一个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;
}
结果如下:
往下看,了解浮点数存储规则!
3.2 浮点数存储规则
num 和 *pfloat 在内存中明明是同一个数,为什么浮点数和整数的解读结果会差别这么大?
一定要搞懂浮点数再计算机内部的表示方法。
根据国际标准IEEE(电气和电子工程协会)754,任意一个二进制浮点数V可以表示成下面的形式:
举个例子:
IEE 754规定:
对于32位的浮点数,最高的1位是符号位S,接着的8位是指数E,剩下的23位为有效数字M。
对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。
IEEE 754对有效数字M集合指数E,还有一些特别规定。
简洁的说:保存M的时候,只保存小数,给M的空间空出1位,可以多存储。读取的时候自动加上1。
至于指数E,情况就比较复杂。
然后,指数E从内存中取出还可以再分成3种情况:
好了,关于浮点数的规则就讲到这里。
解释前面的题目:
注意:
有一些浮点数是不能计算它的存储方式的。
例如:3.14,换成二进制,11.xxxx,小数部分是难以算出来的,所以在一些程序中会有精度丢失的情况出现!!!
数据存储的知识就到这里了,如果对你有所帮助就点个赞吧!!! ^ __ ^
尚想旧情怜奴仆,也曾因梦送钱财------元稹《遣悲怀三首·其二》