计算机内存中存储数据的顺序可以分为大端模式和小端模式,这两种方式的区别在于在存储多字节数据时,字节的顺序不同。
大端模式中,高位字节(最前面的字节)先存储在内存的低地址中,低位字节(最后面的字节)后存储在内存的高地址中。
小端模式中,低位字节(最后面的字节)先存储在内存的低地址中,高位字节(最前面的字节)后存储在内存的高地址中。
下面我们来看看这两者的区别以及如何判断当前系统的字节序。
以一个16位的整数为例,当它的值为0x1234时,
在大端模式下,存储方式为:
地址: 0xfffe 0xffff
+----+----+
数据: | 12 | 34 |
+----+----+而在小端模式下,存储方式为:
地址: 0xfffe 0xffff
+----+----+
数据: | 34 | 12 |
+----+----+可以看到,两种模式下存储的顺序不同。如果我们要在不同系统间进行数据传输,就要考虑到字节序的问题。
C语言提供一个宏定义__BYTE_ORDER__可以用来判断系统使用的字节序。它有以下宏定义:
- __ORDER_LITTLE_ENDIAN__:表示小端模式,低位字节在前。
- __ORDER_BIG_ENDIAN__:表示大端模式,高位字节在前。
- __ORDER_PDP_ENDIAN__:表示PDP(16)模式,按照字节码进行反序。
- 如果当前系统的字节序无法确定,则没有预定义的宏。
通过这个宏定义,就可以很轻松地在代码中处理不同字节序下的数据传输问题。
以下是一个简单的示例程序,用于判断当前机器的字节序:
#include <stdio.h>
int main() {
unsigned int i = 0x12345678;
unsigned char *p = (unsigned char *)&i;
if (*p == 0x78) {
printf("little endian\n");
} else if (*p == 0x12) {
printf("big endian\n");
} else {
printf("unknown endian\n");
}
return 0;
}该程序将一个32位无符号整数0x12345678声明为变量i,然后将其地址的第一个字节强制转换为一个指向无符号字符的指针,并用这个指针来访问这个32位整数的单字节表示。如果第一个(最低)字节是0x78,表示这个机器使用小端模式,否则如果第一个字节是0x12,表示这个机器使用大端模式。如果无法确定字节序,则认为它是未知的。
在实际开发中,当我们需要将数据从一个系统发送到另一个系统时,就需要考虑到字节序的问题。通常,我们使用网络字节序(big endian)来发送数据,例如使用htons()、htonl()等函数将主机字节序转换为网络字节序。然后,接收方通过使用ntohs()、ntohl()等函数将网络字节序转换为主机字节序。这样可以保证不同系统之间的数据传输的正确性。
以下是一些常用的口诀,用于快速记忆大端模式和小端模式的存储方式:
- 大端模式:"高位在前"。
- 小端模式:"低位在前"。
- "大头儿子往前走,小头儿子往后走"。
这些口诀都引用了高位字节和低位字节这两个概念。口诀只是用来辅助记忆的(如果有自己的方法更好),前提还是要自己理解大端模式和小端模式。因此,选择适合自己的口诀方法是很重要的,同时也要通过实践和记忆来加深印象。
