字节序是指当一个数据的长度超过一个字节时的存储顺序。
比如一个int型的数据,所占的字节数为4,那么在存储的时候第一个字节的地址为0x00B8F9F0,这个int数据占用的四个字节的地址为0x00B8F9F0,0x00B8F9F1,0x00B8F9F2,0x00B8F9F3。但是对于a的四个字节的存储顺序,在不同的处理器上可能是不同的。
对于存储顺序,分为大端序和小端序
小端序(Little-Endian):低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
大端序(Big-Endian):高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
这里字节的低位和高位指:
比如
int a = 0x01020304;
左边的01为高位,右边的04为低位这样的顺序
而地址的高端与低端指:
比如
0x00B8F9F0,0x00B8F9F1,0x00B8F9F2,0x00B8F9F3
左边地址值小的为低端,右边地址值大的为高端
小端序:
0x04 | 0x03 | 0x02 | 0x01 |
---|---|---|---|
0x00B8F9F0 | 0x00B8F9F1 | 0x00B8F9F2 | 0x00B8F9F3 |
大端序:
0x01 | 0x02 | 0x03 | 0x04 |
---|---|---|---|
0x00B8F9F0 | 0x00B8F9F1 | 0x00B8F9F2 | 0x00B8F9F3 |
对于存储和传输时的字节序,分为本地序和网络序
本地序指计算机存储的时候所采用的顺序,包括大端序和小端序,网络序指网络传输时采用的字节序,由于网络传输的标准化,所以一般是采用大端序。在发送网络数据之前,需要把本地序转换为网络序,也就是我们一般调用的htonl,htons函数将本地序转换为网络序,接收数据时ntohl,ntohs将网络序转为本地序。
int a = 0x01020304;
cout << "a:" << a << endl;
cout << "a(hex):" << hex << a << endl;
int8_t* b = (int8_t*)&a;
cout << "b[0]:" << hex << (int)*b << endl;
cout << "&b[0]:" << hex << (void*)b << endl;
b++;
cout << "b[1]:" << hex << (int)*b << endl;
cout << "&b[1]:" << hex << (void*)b << endl;
b++;
cout << "b[2]:" << hex << (int)*b << endl;
cout << "&b[2]:" << hex << (void*)b << endl;
b++;
cout << "b[3]:" << hex << (int)*b << endl;
cout << "&b[3]:" << hex << (void*)b << endl;
a = htonl(a);
cout << "\nafter htonl\na:" << a << endl;
cout << "a(hex):" << hex << a << endl;
int8_t* c = (int8_t*)&a;
cout << "c[0]:" << hex << (int)*c << endl;
cout << "&c[0]:" << hex << (void*)c << endl;
c++;
cout << "c[1]:" << hex << (int)*c << endl;
cout << "&c[1]:" << hex << (void*)c << endl;
c++;
cout << "c[2]:" << hex << (int)*c << endl;
cout << "&c[2]:" << hex << (void*)c << endl;
c++;
cout << "c[3]:" << hex << (int)*c << endl;
cout << "&c[3]:" << hex << (void*)c << endl;
输出如下:
a:16909060
a(hex):1020304
b[0]:4
&b[0]:00FEFB00
b[1]:3
&b[1]:00FEFB01
b[2]:2
&b[2]:00FEFB02
b[3]:1
&b[3]:00FEFB03
after htonl
a:4030201
a(hex):4030201
c[0]:1
&c[0]:00FEFB00
c[1]:2
&c[1]:00FEFB01
c[2]:3
&c[2]:00FEFB02
c[3]:4
&c[3]:00FEFB03
我的电脑本地序为小端序,通过htonl转化为大端序。
通过UDP发送的时候
包内数据转换前为:
转换后为:
在转化后发送的数据和原始数据值是一样的。所以一般在传输和接收时最好转换一下字节序。