计算机学科中的很多问题,都是因为概念的抽象模糊,导致理解上的不确定性,增加学习领悟的难度。对于计算机中数据存放次序的问题,很多教材或文章要么含糊其辞,要么凭空飞来结论,让人看的一头雾水。几经周折,结合多篇文章,对内存中数据存放次序终于有了较深入的理解,现记录如下:
一、几个概念:
1.内存中关于数据的存放顺序有三个层次(即三种不同的视角):
1.位序(以一位即bit为单位)-------字节内的bit位与bit位之间的先后顺序
2.字节序(以一字节为单位)-------某类型的字节与字节之间的先后顺序
3.类型序(以若干字节构成的某种类型为单位)-------类型之间的先后顺序
2.内存的扩展方向:
1.递增地址:存放数据时, 自低地址向高地址依次存放, 例如栈
2.递减地址:存放数据时, 自高地址向低地址依次存放, 例如堆
题外话:Linux系统中,用虚拟内存映射到物理内存的方式来管理内存空间。操作系统占用的内存空间称为系统空间, 用户程序占用的空间称为用户空间,在用户空间中,有栈和堆,两块内存区是连在一起 ,但是栈是地址递增,堆是地址。
3.大端模式与小端模式
12345678
左 <-------> 右
看上面的数字顺序,我们可以从右向左读87654321,也可以从左向右读12345678,那么计算机也一样,在读入这串数据时(即将这串数据装入内存),它也可以按从右向左或从左向右的顺序读入
小端法;即计算机读入这串数据时,是按照从右向左的顺序,依此将87654321存放到内存的
大端法:即计算机读入这串数据时,是按照从左向右的顺序,依此将12345678存放到内存的
弄明白了大小端模式,下面我们来结合前面地址增长方向和位序、字节序来看看,内存中的数据到底是怎么来存放的
二、内存中数据的真实存放次序
1.地址递增情况
(1).位序
以二进制10110101(B)为例:
左------>10110101<-------右
小端模式:按位,自右向左依次将1 0 1 0 1 1 0 1存放在0地址单元中的第0位到第7位, 如图1-1:
图1-1
大端模式:按位,自左向右依次将1 0 1 1 0 1 0 1存放在0地址单元中的第0位到第7位, 如图1-2:
图1-2
(2).字节序
以十六进制数0x12345678(12、34、56、78分别各自构成一个字节,由于以字节为单位,故将忽略字节内的位序))为例:
左------->0x12 34 56 78<-------右
小端模式:按字节, 自右向左依次将78 56 34 12这四个字节存放在自0地址开始的4个内存单元(每个单元存放一个字节)中, 如图2-1:
图2-1
大端模式:按字节, 自左向右依次将12 34 56 78这四个字节存放在自0地址开始的4个内存单元(每个单元存放一个字节)中, 如图2-2:
图2-2
(3).综合字节序与位序
【总结】可见无论是位序还是字节序, 小端模式总是自右向左的读取数据,而大端模式总是自左向右的读取数据, 区别仅在于是按位还是按字节,因此,对于任意一个数据而言可以总结如下:
以数据0x12345678(00010010 00110100 01010110 01111000B)为例
小端模式:如图3-1
图3-1
大端模式:如图3-2
图3-2
2.地址递减情况
小端模式:将数据自右向左依次逐位或逐字节地填入到自高地址开始逐渐递减的内存中
大端模式:将数据自左向右依次逐位或逐字节地填入到自高地址开始逐渐递减的内存中
【ps】:很多教材或文章中,总用低地址,高地址和低字节、高字节做区分和记忆,实际这样很不方便记忆,而且也不易理解,同时,只适用栈这样的地址递增的情况,而不适用于堆这种内存递减的情况,因此本文章弃用这种方法,只按数据书写格式的自左向右与自右向左来区分大端模式与小端模式,方便记忆和理解
三、结构体中各数据类型内存存放次序与位域
1.结构体中各类型元素,按其声明的先后顺序,依次存放
例如:下面的结构体,对于内存递增情况,自低地址向高地址依此存放a b c
struct data
{
int a;
short b;
char c;
};
2.位域:指定变量占用几位bit位
例如:下面结构体中,int型的a只占用3位bit, short型的b占用9位bit, 而char型的c占用4位bit,整个结构体共占用16位,即共占用两个字节
struct data
{
int a : 3; 假设: a为110
short b : 9; b为101011001
char c : 4; c为1101
小端模式:如图4-1
图4-1
大端模式:如图4-2
图4-2
四、函数参数入栈
1.一般可以通过宏命令指定参数入栈方式:参数自右向左逐个依次入栈,还是自左向右依次入栈。一般默认参数入栈方式为自右向左
例如:函数add(int a, int b);其参数入栈次序按默认为自右向左依次入栈,即b先入栈,然后a再入栈
2.入栈的位序与字节序
(1).入栈的位序
以long long型十进制数1427195721448768429为例
无论大/小端模式,其入栈的次序都是相同:对于一块内存上的数据:
入栈顺序:最高地址所对应的字节中的最高位最先入栈, 然后是最好字节中的次高位入栈,…, 最后是最低地址所对应的字节中的最低位入栈。
出栈顺序:栈顶字节中的最高位弹出到最低地址所对应的字节中的最低位, …栈底字节中最低位弹出到最高地址所对应的最高位
这样设计入栈顺序,是为了出栈后的顺序与入栈前的顺序保持一致
小端模式与大端模式的区别在于各自不同的字节序与字节内的位序
小端模式(如图5-1):
图5-1
大端模式(如图5-2):
图5-2
(2).入栈的字节序
入栈顺序:最高地址对应的字节先入栈,然后第二高地址对应的字节入栈,...,最后最低地址对应的字节最后入栈
出栈顺序:栈顶字节弹出到最低地址对应的字节, ..., 栈底字节弹出到最高地址对应的字节
3.入栈字节数限制
一般入栈的字节数为一个机器字长(32位机为4字节), 对于大于4字节的类型,如long long其入栈情况前面已经讨论过,无论是大端模式,还是小端模式,即其最高地址对应的字节先入栈, ..., 最低地址对应的字节最后入栈, 而字节内部最高位最先入栈, 最低位最后入栈
对于小于4字节的类型, 如char和short在入栈时, 将其按低地址对齐,
如果是无符号数, 则在其后补的高地址对应的字节内补0, 例如char型的0x12只占用1个字节, 为将其补全为4个字节,可在其后递增的地址上补上3个字节的0
如果是有符号位, 则在其后补的高地址对应的字节内补符号位, 例如short型的-25只占用2个字节, 为将其补全为4个字节,可在其后递增的地址上补上2个字节的1(-25的符号位是负的,因此补1)