1. 概念

MSB:Most Significant Bit  ------- 最高有效位    

LSB:Least Significant Bit ------- 最低有效位

大端模式(big-edian)    big-endian:MSB存放在最低端的地址上。

小端模式(little-endian)     little-endian:LSB存放在最低端的地址上。 

2. 判断

在C语言中,不同于结构体,共用体(联合体)中的几种不同类型的变量存放在同一段内存单元中。

利用这一特点,可以用联合体变量判断ARM或x86环境下,存储系统是是大端还是小端模式。

#include "stdio.h"
int main()
{
   union w
  {
    int a;  //4 bytes
    char b; //1 byte
  } c;
  c.a=1;
  if (c.b==1)
  printf("It is Little_endian!\n");
  else
  printf("It is Big_endian!\n");
  return 1;
}

说明:
(1)  在c中,联合体(共用体)的数据成员都是从低地址开始存放。
(2)  若是小端模式,由低地址到高地址c.a存放为0x01 00 00 00,c.b被赋值为0x01;
  ————————————————————————————
   地址 0x00000000 0x00000001 0x00000002 0x00000003
   c.a                   01                00                  00                00
   c.b                   01                00       
  ————————————————————————————  
(3) 若是大端模式,由低地址到高地址c.a存放为0x00 00 00 01,c.b被赋值为0x0;
  ————————————————————————————
   地址 0x00000000 0x00000001 0x00000002 0x00000003
   c.a                  00                  00                 00                01
   c.b                  00                  00                
  ————————————————————————————  

(4)  根据c.b的值的情况就可以判断cpu的模式了,现在XP环境下的intel CPU是小端模式。 

 

3. 转换

typedef unsigned short int uint16;
 
typedef unsigned long  int uint32;
 
 
 
// 短整型大小端互换
 
#define BigLittleSwap16(A)  ((((uint16)(A) & 0xff00) >> 8) | \
 
                             (((uint16)(A) & 0x00ff) << 8))
 
 
 
// 长整型大小端互换
 
#define BigLittleSwap32(A)  ((((uint32)(A) & 0xff000000) >> 24) | \
 
                             (((uint32)(A) & 0x00ff0000) >> 8)  | \
 
                             (((uint32)(A) & 0x0000ff00) << 8)  | \
 
                             (((uint32)(A) & 0x000000ff) << 24))
 
 
 
// 本机大端返回1,小端返回0
 
int checkCPUendian()
 
{
 
       union{
 
              unsigned long int i;
 
              unsigned char s[4];
 
       }c;
 
 
 
       c.i = 0x12345678;
 
       return (0x12 == c.s[0]);
 
}

4. 网络字节

TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。 

网络字节顺序是“所见即所得”的顺序。而Intel类型的CPU的字节顺序与此相反。

比如上面的 short B=0102H(十六进制,每两位表示一个字节的宽度)。

所见到的是“0102”,按一般数学常识,数轴从左到右的方向增加,即内存地址从左到右增加的话,在内存中这个 short B的字节顺序是: 01 02  这就是网络字节顺序。

所见到的顺序和在内存中的顺序是一致的! 

5. htonl、ntohl、htons、ntohs函数实现 

// 模拟htonl函数,本机字节序转网络字节序
 
unsigned long int HtoNl(unsigned long int h)
 
{
 
       // 若本机为大端,与网络字节序同,直接返回
 
       // 若本机为小端,转换成大端再返回
 
       return checkCPUendian() ? h : BigLittleSwap32(h);
 
}
 
 
 
// 模拟ntohl函数,网络字节序转本机字节序
 
unsigned long int NtoHl(unsigned long int n)
 
{
 
       // 若本机为大端,与网络字节序同,直接返回
 
       // 若本机为小端,网络数据转换成小端再返回
 
       return checkCPUendian() ? n : BigLittleSwap32(n);
 
}
 
 
 
// 模拟htons函数,本机字节序转网络字节序
 
unsigned short int HtoNs(unsigned short int h)
 
{
 
       // 若本机为大端,与网络字节序同,直接返回
 
       // 若本机为小端,转换成大端再返回
 
       return checkCPUendian() ? h : BigLittleSwap16(h);
 
}
 
 
 
// 模拟ntohs函数,网络字节序转本机字节序
 
unsigned short int NtoHs(unsigned short int n)
 
{
 
       // 若本机为大端,与网络字节序同,直接返回
 
       // 若本机为小端,网络数据转换成小端再返回
 
       return checkCPUendian() ? n : BigLittleSwap16(n);
 
}

参考文献:

【1】            博主:Berry029

【2】             博主:ysdaniel