也可以说:
1.小端法(Little-Endian)就是低位字节排放在内存的低地址端即该值的起始地址,高位字节排放在内存的高地址端。
2.大端法(Big-Endian)就是高位字节排放在内存的低地址端即该值的起始地址,低位字节排放在内存的高地址端。
举个简单的例子,对于整形0x12345678。它在大端法和小端法的系统内中,分别如图1所示的方式存放。
网络字节序:与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big endian(大端)排序方式。
我们知道网络上的数据流是字节流,对于一个多字节数值,在进行网络传输的时候,先传递哪个字节?也就是说,当接收端收到第一个字节的时候,它是将这个字节作为高位还是低位来处理呢?
网络字节序定义:收到的第一个字节被当作高位看待,这就要求发送端发送的第一个字节应当是高位。而在发送端发送数据时,发送的第一个字节是该数字在内存中起始地址对应的字节。可见多字节数值在发送前,在内存中数值应该以大端法存放。
网络字节序说是大端字节序。
比如我们经过网络发送0x12345678这个整形,在80X86平台中,它是以小端法存放的,在发送前需要使用系统提供的htonl将其转换成大端法存放,如图2所示。 网络字节序是确定的,而主机字节序的多样性往往是混淆的原因!
htonl 把unsigned long类型从主机序转换到网络序
ntohs 把unsigned short类型从网络序转换到主机序
ntohl 把unsigned long类型从网络序转换到主机序
在使用little endian的系统中 这些函数会把 字节序进行转换
在使用big endian类型的系统中 这些函数会定义成空宏
同样 在网络程序开发时 或是 跨平台开发时 也应该注意保证只用一种字节序 不然两方的解释不一样就会产生bug.
2、不同的CPU上运行不同的操作系统, 字节序也是不同的,参见下表。
处理器 操作系统 字节排序
Alpha 全部 Little endian
HP-PA NT Little endian
HP-PA UNIX Big endian
Intelx86 全部 Little endian
下面是一个检验本机字节序的简便方法:
//判断本机的字节序
//返回true表为小段序。返回false表示为大段序
bool am_little_endian ()
{
unsigned short i=1;
return (int)*((char *)(&i)) ? true : false;
}
int main()
{
if(am_little_endian())
{
printf("本机字节序为小段序!\n");
}
else
{
printf("本机字节序为大段序!\n");
}
return 0;
}
1 | #include <stdio.h> |
2 | #include <netinet/in.h> |
3 | int main() |
4 | { |
5 | int i_num = 0x12345678; |
6 | printf("[0]:0x%x\n", *((char *)&i_num + 0)); |
7 | printf("[1]:0x%x\n", *((char *)&i_num + 1)); |
8 | printf("[2]:0x%x\n", *((char *)&i_num + 2)); |
9 | printf("[3]:0x%x\n", *((char *)&i_num + 3)); |
10 | |
11 | i_num = htonl(i_num); |
12 | printf("[0]:0x%x\n", *((char *)&i_num + 0)); |
13 | printf("[1]:0x%x\n", *((char *)&i_num + 1)); |
14 | printf("[2]:0x%x\n", *((char *)&i_num + 2)); |
15 | printf("[3]:0x%x\n", *((char *)&i_num + 3)); |
16 | |
17 | return 0; |
18 | } |
在80X86CPU平台上,执行该程序得到如下结果:
[0]:0x78
[1]:0x56
[2]:0x34
[3]:0x12
[0]:0x12
[1]:0x34
[2]:0x56
[3]:0x78
分析结果,在80X86平台上,系统将多字节中的低位存储在变量起始地址,使用小端法。htonl将i_num转换成网络字节序,可见网络字节序是大端法。
总结点:80X86使用小端法,网络字节序使用大端法。