字节序

字节序又称为端序或者尾序,顾名思义就字节的顺序。专业的讲就是指在存储器或者在通信链路中,由多字节组成的数据的排列方式。

对于多字节数据的顺序有两种,一种是数据的高位存储在内存的低地址处,称为小端序,另一种是数据的高位存在内存的高地址出,称为大端序。

小端序

用小端序表示的数据,数据的高位在内存地址的低位。下面用一个unsigned long类型的数据0x12345678来举例说明。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
  #include<stdio.h>
  #include<arpa/inet.h>
  int main()
  {
      printf("unsigned int:%ld\n",sizeof(unsigned long));
      printf("unsigned char:%ld\n",sizeof(unsigned char));
      unsigned int a=0x12345678;
      unsigned char *pointer=(unsigned char *)(&a);
      printf("host :%p:%0x\t%p:%0x\t%p:%0x\t%p:%0x\n",&pointer[0],pointer[0],&pointer[1],pointer[1],&pointer[2],pointer[2],&pointer[3],pointer[3]);
      return 0;
   }
 程序运行结果:
unsigned int:8
unsigned char:1
host :0x7ffee0b4d2dc:78 0x7ffee0b4d2dd:56       0x7ffee0b4d2de:34       0x7ffee0b4d2df:12

存储的数据是unsigned long类型的数据,数据的高位是0x12,但是在实际的内存分布来看,数据的高位位于低地址而数据的低位在高字节地址。

这样存储的好处就是计算机可以先处理数据低位,在处理数据高位,方便计算机进行运算。

大端序

大端序的高地址位存储的是数据低位,低地址存储数据高位。

大端序方便人们进行阅读,因此在网络传输和存储时都采用大端序。在网络编程,利用socket通信时,要将主机字节序也就是小端序转换成网络字节序也就是大端序,才能进行发送。同理,接收数据时,也要将网络字节序转换为主机字节序,计算机才能对数据进行处理。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
  #include<stdio.h>
  #include<arpa/inet.h>
  int main()
  {
      unsigned long a=0x12345678;
      unsigned char *pointer=(unsigned char *)(&a);
 
      unsigned long b=htonl(a);
      pointer=(unsigned char *)(&b);
      printf("network :%p:%0x\t%p:%0x\t%p:%0x\t%p:%0x\n",&pointer[0],pointer[0],&pointer[1],pointer[1],&pointer[2],pointer[2],&pointer[3],pointer[3);]    
 
      return 0;
  }
 输出结果:network :0x7ffd9416f4d8:12      0x7ffd9416f4d9:34       0x7ffd9416f4da:56       0x7ffd9416f4db:78

通过htonl函数可以将主机字节序(小端)转换成网络字节序(大端),经过转换后,数据的低地址位存储数据的高位。

判断本机的字节序

下面是一段简单的代码可以判断本机的字节序。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
  #include<stdio.h>
  #include<arpa/inet.h>
  void judge()
  {
      int a = 0x12345678;
      if( *((char*)&a) == 0x12)
          printf("big endian \n");
      else
          printf("little endian \n");
  }
  int main()
  {
      judge();
      return 0;
  }