一、大端小端概念
字节顺序是指在一个多字节的数据中,最高有效位(MSB)和最低有效位(LSB)的存放顺序。有两种常见的字节顺序:大端(Big Endian)和小端(Little Endian)。大端是指MSB存放在低地址,LSB存放在高地址;小端是指MSB存放在高地址,LSB存放在低地址。
大端和小端是指数据在内存中的存储模式,它由 CPU 决定:
- 大端模式(Big-endian)是指将数据的低位(比如 1234 中的 34 就是低位)放在内存的高地址上,而数据的高位(比如 1234 中的 12 就是高位)放在内存的低地址上。
- 小端模式(Little-endian)是指将数据的低位放在内存的低地址上,而数据的高位放在内存的高地址上。举个例子,比如向内存地址为 0X1000 的地址写入 0X12345678 这个四字节16进制数,在大端和小端模式下,内存中的表示形式为:
| 地址 | 大端模式 | 小端模式 |
| ------- | -------- | -------- |
| 0X1000 | 12 | 78 |
| 0X1001 | 34 | 56 |
| 0X1002 | 56 | 34 |
| 0X1003 | 78 | 12 |大端和小端模式的优缺点各有不同:
- 大端模式符合人类习惯,方便阅读和调试;也符合字符串比较时单词的顺序;但是不符合计算机处理数据时从低位到高位的方式。
- 小端模式符合计算机处理数据时从低位到高位的方式,方便运算和转换;但是不符合人类习惯,也不符合字符串比较时单词的顺序。
在同一台计算机内部,字节顺序通常不会引起问题,只有当程序同时以不同的单位(比如字或字节)访问同一块内存时,才会注意到差异。但是当不同字节顺序的计算机之间交换数据时,就会出现问题。小端顺序也会导致字符串比较时,单词的顺序和正常的顺序不一致。字符串在寄存器中看起来是“倒着”的。
二、字节对齐概念
在很多计算机中,访问大于一个字节的对象时,必须对齐。对齐是指一个大小为s字节的对象在地址A处访问时,A能被s整除。为什么有人设计一个有对齐限制的计算机呢?不对齐会导致硬件复杂化,因为内存通常是按照一个字或双字的边界对齐的。一个不对齐的内存访问可能需要多个对齐的内存引用。因此,即使在允许不对齐访问的计算机中,使用对齐访问的程序也会运行得更快。
字节对齐是指在多字节数据访问时,要求数据的起始地址能被其占用空间的整数倍整除。比如一个四字节的数据,要求其起始地址能被4整除。如果不满足这个要求,就称为不对齐。
举个例子,假设有一个结构体如下:
```c
struct student
{
char name[10];
int age;
double score;
};
```如果按照字节对齐的原则,这个结构体占用空间为24字节,因为每个成员都要对齐到自己大小的整数倍。具体如下:
| 成员 | 起始地址 | 占用空间 | 对齐空间 |
| ------ | -------- | -------- | -------- |
| name | 0 | 10 | 12 |
| age | 12 | 4 | 4 |
| score | 16 | 8 | 8 |如果不按照字节对齐的原则,这个结构体占用空间为22字节,因为每个成员都紧密排列。具体如下:
| 成员 | 起始地址 | 占用空间 |
| ------ | -------- | -------- |
| name | 0 | 10 |
| age | 10 | 4 |
| score | 14 | 8 |字节对齐有什么好处呢?主要有两个:
- 提高访问效率。如果数据不对齐,可能需要多次访问内存才能获取完整的数据;而如果数据对齐,一次访问就能获取完整的数据。
- 避免兼容性问题。不同的编译器或平台可能对字节对齐有不同的要求或默认值,如果数据不对齐,可能导致数据解析错误;而如果数据对齐,就能保证数据的一致性。