字节序是指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序。
主机字节序:
不同的CPU有不同的字节序类型,这些字节序是指整数在内存中保存的顺序,这个叫做主机字节序。
最常见的有两种:
1. Little endian:就是低位字节排放在内存的低地址端即该值的起始地址,高位字节排放在内存的高地址端。
2. Big endian:就是高位字节排放在内存的低地址端即该值的起始地址,低位字节排放在内存的高地址端。
网络字节序:
网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。
网络字节顺序采用Big endian排序方式,即大端字节序。
为了进行转换,bsd socket提供了转换的函数,有下面四个:
htons 把unsigned short类型从主机序转换到网络序
htonl 把unsigned long类型从主机序转换到网络序
ntohs 把unsigned short类型从网络序转换到主机序
ntohl 把unsigned long类型从网络序转换到主机序
注:在使用little endian的系统中,这些函数会把字节序进行转换 。
在使用big endian类型的系统中,这些函数会定义成空宏。
同样 在网络程序开发时 或是跨平台开发时 也应该注意保证只用一种字节序,不然两方的解释不一样就会产生bug.
举个简单的例子,如果我们将0x1234abcd写入到以0x0000开始的内存中,则结果为
字节序测试程序
不同cpu平台上字节序通常也不一样,下面写个简单的C程序,它可以测试不同平台上的字节序。
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转换成网络字节序,可见网络字节序是大端法。
程序:写一个C函数,若处理器是Big_endian,则返回 0;若是Little_endian,则返回1;
int checkSystem()
{
union check
{
int i;
char ch;
}test;
test.i = 1;
return (test.ch == 1);
}
这是利用union数据类型的特点编写的程序,是不是对你很有启发。