大小端




#include <stdio.h>

int main()
{
    int i = 0x11223344;
    char * a = (char *)&i;
    int j;
    printf("Little Endian:\n");
    for (j = 0; j < 4; j++)
        printf("%x\n", a[j]);
    printf("\n");

    i = htonl(i);
    printf("Big    Endian:\n");
    for (j = 0; j < 4; j++)
        printf("%x\n", a[j]);
}

----------------------------------
Little Endian:
44
33
22
11

Big    Endian:
11
22
33
44


----------------------------------
htonl, htons, ntohl, ntohs - convert values between host and network byte order

    #include <arpa/inet.h>
    uint32_t htonl(uint32_t hostlong);
    uint16_t htons(uint16_t hostshort);
    uint32_t ntohl(uint32_t netlong);
    uint16_t ntohs(uint16_t netshort);


----------------------------------
#include <stdio.h>

int main()
{
    unsigned int i = 0xABCDEF78;
    printf("Little Endian:\n");
    printf("i = %X\n", i);

    i = htonl(i);    // 字節序轉化爲小字節序
    printf("Big    Endian:\n");
    printf("i = %X\n", i);
}



----------------------------------
Little Endian:
i = ABCDEF78
    // (31 ~ 0)
Big    Endian:
i = 78EFCDAB    // (0 ~ 31)

深入理解字節序: 字節序表示字節內部(8 bits)的順序是一樣的,不存在順序顛倒的問題。也就是說unsigned int類型的數據(32 bits -- 4 Bytes),大字節序和小字節序在整體順序(4 Bytes)是顛倒的,局部順序(字節內部)是一致的、不變的。


 

  1. /** 
  2. * @file Code_Convert.h 
  3. * @brief 
  4. * @author Donhao 
  5. * @date 2010-7-17 12:33:16 
  6. * @version 
  7. * <pre><b>copyright: </b></pre> 
  8. * <pre><b>All rights reserved.</b></pre> 
  9. * <pre><b>modification:</b></pre> 
  10. * <pre>Write modifications here.</pre> 
  11. */  
  12. #ifndef _CODE_CONVERT_H  
  13. #define _CODE_CONVERT_H  
  14.   
  15. /** 
  16. * @defgroup 主機字節序與網絡字節序之間的轉換 
  17. * @brief 
  18. * 
  19. * Detailed description. 
  20. * @{ 
  21. */  
  22.   
  23. /** 
  24. * @brief Code_Is_Net 
  25. * 
  26. * 判斷本機是主機字節序還是網絡字節序. 
  27. * @return BOOL 
  28. */  
  29. BOOL Code_Is_Net(void);  
  30.   
  31. /** 
  32. * @brief Code_H2N16 
  33. * 
  34. * @param[in] x 
  35. * @return unsigned short 
  36. */  
  37. unsigned short Code_H2N16(unsigned short x);  
  38.   
  39. /** 
  40. * @brief Code_H2N32 
  41. * 
  42. * @param[in] x 
  43. * @return unsigned long 
  44. */  
  45. unsigned long Code_H2N32(unsigned long x);  
  46. /** @} */  
  47.   
  48. #endif  

 

  1. /** 
  2. * @file Code_Convert.c 
  3. * @brief 
  4. * @author Donhao 
  5. * @date 2010-7-17 12:33:31 
  6. * @version 
  7. * <pre><b>All rights reserved.</b></pre> 
  8. * <pre><b>modification:</b></pre> 
  9. * <pre>Write modifications here.</pre> 
  10. */  
  11.   
  12. #include "Code_Convert.h"  
  13.   
  14. BOOL Code_Is_Net(void)  
  15. {  
  16.     unsigned short value = 0x55AA;  
  17.   
  18.     if (0x55 == *((unsigned char*)(&value)))  
  19.     {  
  20.         return TRUE;  
  21.     }  
  22.     else  
  23.     {  
  24.         return FALSE;  
  25.     }  
  26. }  
  27.   
  28. unsigned short Code_H2N16(unsigned short x)  
  29. {  
  30.     unsigned short y = 0;  
  31.     unsigned short z = 0;  
  32.   
  33.     z = x & 0x00FF;  
  34.     y = z << 8;  
  35.     z = x & 0xFF00;  
  36.     y += (z >> 8);  
  37.     return y;  
  38. }  
  39.   
  40. unsigned long Code_H2N32(unsigned long x)  
  41. {  
  42.     unsigned long y = 0;  
  43.     unsigned long z = 0;  
  44.   
  45.     z = x & 0x000000FF;  
  46.     y = z << 24;  
  47.     z = x & 0x0000FF00;  
  48.     y += (z << 8);  
  49.     z = x & 0x00FF0000;  
  50.     y += (z >> 8);  
  51.     z = x & 0xFF000000;  
  52.     y += (z >> 24);  
  53.     return y;  
  54. }  

在網絡上傳輸數據時,由於數據傳輸的兩端可能對應不同的硬件平臺,採用的存儲字節順序也可能不一致,因此 TCP/IP 協議規定了在網絡上必須採用網絡字節順序(也就是大端模式)
通過對大小端的存儲原理分析可發現,對於 char 型數據,由於其只佔一個字節,所以不存在這個問題,這也是一般情況下把數據緩衝區定義成 char 類型的原因之一。對於 IP 地址、端口號等非 char 型數據,必須在數據發送到網絡上之前將其轉換成大端模式,在接收到數據之後再將其轉換成符合接收端主機的存儲模式。

Linux 系統爲大小端模式的轉換提供了 4 個函數,輸入 man byteorder 命令可得函數原型:
Some systems require the inclusion of <netinet/in.h> instead of <arpa/inet.h>.

引用
#include <arpa/inet.h>

uint32_t htonl(uint32_t hostlong);

uint16_t htons(uint16_t hostshort);

uint32_t ntohl(uint32_t netlong);

uint16_t ntohs(uint16_t netshort);


htonl 表示 host to network long ,用於將主機 unsigned int 型數據轉換成網絡字節順序;
htons 表示 host to network short ,用於將主機 unsigned short 型數據轉換成網絡字節順序;
ntohl、ntohs 的功能分別與 htonl、htons 相反。



判斷字節序:
main()
{
   int x = 0x1;

   if ((*(char *)&x) == 0x1)
      printf("little endian!\n");
   else
      printf("big endian!\n");

}

字節序轉換:
ntohs(n) = __swab16(n),
ntohl = __swab32(n)。
__swab16與__swab32函數定義如下所示。

#define ___swab16(x)
{
            __u16 __x = (x);
            ((__u16)(
                        (((__u16)(__x) & (__u16)0x00ffU) << 8) |
                        (((__u16)(__x) & (__u16)0xff00U) >> 8) ));
}
#define ___swab32(x)
{
            __u32 __x = (x);
            ((__u32)(
                        (((__u32)(__x) & (__u32)0x000000ffUL) << 24) |
                        (((__u32)(__x) & (__u32)0x0000ff00UL) <<  8) |
                        (((__u32)(__x) & (__u32)0x00ff0000UL) >>  8) |
                        (((__u32)(__x) & (__u32)0xff000000UL) >> 24) ));
}

寫法很嚴謹。簡化版的:
#define swab32(x) ((x&0x000000ff) << 24 | (x&0x0000ff00) << 8 | (x&0x00ff0000) >> 8 | (x&0xff000000) >> 24)

#define swab16(x) ((x&0x00ff) << 8 | (x&0xff00) >> 8)




#if defined(BIG_ENDIAN) && !defined(LITTLE_ENDIAN)

   #define htons(A) (A)
   #define htonl(A) (A)
   #define ntohs(A) (A)
   #define ntohl(A) (A)

#elif defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)

   #define htons(A) ((((uint16_t)(A) & 0xff00) >> 8 ) | \\
                      (((uint16_t)(A) & 0x00ff) << 8 ))
   #define htonl(A) ((((uint32_t)(A) & 0xff000000) >> 24) | \\
                      (((uint32_t)(A) & 0x00ff0000) >> 8 ) | \\
                      (((uint32_t)(A) & 0x0000ff00) << 8 ) | \\
                      (((uint32_t)(A) & 0x000000ff) << 24))
   #define ntohs     htons
   #define ntohl     htohl

#else

   #error Either BIG_ENDIAN or LITTLE_ENDIAN must be #defined, but not both.

#endif



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章