C语言- - 剖析数据在内存中的存储
前言
还记得之前的指针类文章,我说过数据在内存中的存储是倒着存的。那么为什么是倒着存的呢?今天我们就来剖析一下原理,找出这个问题的答案。
长文警告!
一、数据类型
我们先来复习常见的数据类型
- char — —字符数据类型。占用 1 个字节
- short — — 短整形。占用 2 个字节
- int — — 整形。占用 4 个字节
- long — — 长整形。在x64环境占 8 个字节,在x86环占 4 个字节
- long long — —-更长的整形。C99独占,占 8 个字节
- float — —单精度浮点型。占用 4 个字节
- double — — 双精度浮点型。占用 8 个字节
那么,这么多数据类型,他们的意义是什么呢?
其实,当你使用某个数据类型时,实际上是向内存申请开辟某某个字节用来存储数据。
其中还能细分
char
unsigned char
signed char
…(其余的各种类型同理)
unsigned代表无符号型
signed代表有符号型
这里面,除了char的类型是未定义(取决于编译器)其他的比如int啊,long什么的都是默认signed类型。
那么,为什么要区分呢?
数据在存储时,我这举个例子:
比如温度。温度是有零下几度零上几度这一说的。这里以-5度与10度来举例。
int在内存中占 4 个字节,一个字节是八位(1 byte = 8 bit)所以要占32位
10000000000000000000000000000101(-5)
00000000000000000000000000001010(10)
这里:最高位代表的是符号位,1表示负数0表示正数。数据是这么存的,所以一共占用了2^31这么多位。
但是日常生活中总有那些没有负数的数据。比如身高,比如体重。他们就应该使用unsiged类型的数据。再举个例子比如身高是193cm
00000000000000000000000011000001(193)
因为unsigned是无符号型,所以最高位不用管是否是正负数,所以他一共会占用2^32这么多位。
所以,当你创建变量时,总是正数的变量应该使用unsigned类型比较规范。
1.构造类型
- 数组类型:
比如 int arr[3] 实际就是 int[3],只是写法不同 - 结构体类型: struct
- 枚举类型: enum
- 联合类型:union
2.指针类型
- int* pi;
- float* pf;
- char* pc;
- void* pv;
3.空类型
void就是空类型,或者叫无类型。
通常用于函数的返回类型、函数的参数、指针类型
这里的返回类型指的是:函数无返回类型
函数的参数表示:函数不需要传递参数
其中void* 也被称为最万能的指针类型
二、整形在内存中的存储
1.原码、反码、补码
注:正整数原反补码均相同
首先,必须先知道一个重要的概念:数据在内存中是以二进制的数进行存储的,并且是以补码的形式进行存储的(这里浮点数除外吗,我么后面会谈论到)
原码:原码是一种直接表示数值的方法
反码:反码是一种用于简化二进制加减运算的表示方法
补码:补码是目前计算机系统中最常用来表示的方法
原码反码补码的运算规律是什么呢?
比如25 与 -25
25的原码:
00000000 00000000 00000000 00011001
0x 00 00 00. 19
反码:
00000000 00000000 00000000 00011001
补码:
00000000 00000000 00000000 00011001
-25的原码:
10000000 00000000 00000000 00011001
0x 80 00 00 19
反码:
11111111 11111111 11111111 11100110
0x FF FF FF E6
补码:
11111111 11111111 11111111 11100111
0x FF FF FF E7
总结一下规律:
除了正数外,原码就等于是数据本身,符号位为1
反码就是原码符号位不变,其他位按位取反
补码就是反码+1
反过来也一样,补码取反+1就是原码
核心操作:取反+1
而对于二进制转16进制:
先写出十六进制的标识0x,
然后每四位二进制位计算一次,最后拼起来就是十六进制了
内存中存放的是二进制位,十六进制一般是因为二进制位看的不方便才显示的,本质上存放的是二进制位
对于整形来说:数据存放在内存中实际存的是补码。
为什么呢?
- 在计算机系统中,数值一律用补码来表示和存储。原因就是可以让符号位和数值域统一处理。
- 加减法也可以统一处理。然后,补码与原码互相转换其运算过程是相通的,不需要额外的硬件电路。
举个例子:
比如 1 - 1, 1- 1可以转换成1 + (-1)
1的补码: 00000000 00000000 00000000 00000001
-1的补码:11111111 11111111 11111111 11111111
让这俩相加:
11111111 11111111 11111111 11111111(+1)
得到1 00000000 00000000 00000000 00000000
变成33位了,但是最高位会抛弃,所以得到全零。同时这也是 0 的补码。
2.大端存储与小端存储
前面的文章我们都说数据是存储在内存中的,并且是以相反的顺序存储的。但是为什么是反着