glibc之字節序

   我們知道,字節序分爲big-endian 和 little-endian ,採用大端的機器有IBM體系結構,相反intel體系結構主機則採用小端。另外我們需要知道的是,在網絡編程中,字節序爲大端,所以我們要實現主機字節序到網絡字節序的轉換。這裏有一個需要說明的是,爲什麼網絡字節序需要採用大端。主要是大端有一個特點,我們書寫某個數的16進制形式(從左至右:高字節->低字節)和內存中存儲形式一樣的(從左至右:低地址->高地址)是一樣的,外觀一樣,所以網絡字節序好理解(個人觀點,呵呵),從括號中我們可以知道。

   (附:在網絡傳輸中,採用big-endian序,對於0x0A0B0C0D ,傳輸順序就是0A 0B 0C 0D(傳輸的時候從低地址開始 ,因此big-endian作爲network byte order,little-endian作爲host byte order。爲什麼X86存儲會使用little-endian,起初我想對於位運算,尤其是位移運算,little-endian很方便,但轉念一想,big-endian也方便啊,無非是左移和右移的區別而已,但little-endian的優勢在於unsigned char/short/int/long類型轉換時,存儲位置無需改變。如short a  = 0x1234;小字節序主機存儲內存如下:

   add      add+1

   34,        12
  2011-07-22更新)

   int b =  (int)a  後,b內存存儲爲:

  

    add                        add+3

    34   ,   12 ,     00 ,   00

    可以知道,類型轉換非常簡單,只在後面添加0x0000即可)

 

 

  大端字節序即 最重要的字節(高位,也稱爲the most significance of bytes)存放在低地址(前面的地址,即前面),高位在前,也就是我們書寫的形式。

    比如:0x12345678 。

    如果採用大端,在內存中存放如下:

    add                        add+3

    12   ,   34 ,     56 ,   78

 

    和我們書寫形式是一樣的。

    如果採用小端,將存放如下:

    add                        add+3

    78   ,   56 ,     34 ,   12

 

   總結如下:大端即高位(字節)在前(低地址),小端即低位(字節)在前(低地址)

 

 

   有了上面的討論,本文具體討論下glibc下面字節序的相關實現機制。本文主要涉及的庫文件包括 :

    /usr/include/bits/endian.h

    /usr/include/endian.h

    /usr/include/bits/byteswap.h

    /usr/include/byteswap.h

 

 

////////////////////////////////////////////////////////////////////////////////////

  /usr/include/bits/endian.h

  /* This file defines `__BYTE_ORDER' for the particular machine.  */

 該文件主要定義了具體的機器的字節序,如對於Intel i386是小端字節序

  1 /* i386 is little-endian.  */
  2
  3 #ifndef _ENDIAN_H
  4 # error "Never use <bits/endian.h> directly; include <endian.h> instead."
  5 #endif

  //以上的預編譯指令用來阻止直接包含bits/endian.h頭文件,因爲宏 _ENDIAN_H是在/usr/include/endian.h定義的,如果沒有包含/usr/include/endian.h文件,則對應的宏沒定義,通過#error產生預編譯錯誤,也就是說,系統提供給外部的接口只能是

include/endian.h 頭文件 ,與機器無關,而bits/endian.h 文件是於與特定機器相關的。這也就提高了程序的可移植性,因爲系統提供給外部的頭文件include/endian.h是與系統無關的。

6
  7 #define __BYTE_ORDER __LITTLE_ENDIAN

////////////////////////////////////////////////////////////////////////////////////

 ///usr/include/endian.h文件內容如下:
 19 #ifndef _ENDIAN_H
 20 #define _ENDIAN_H   1
 21
 22 #include <features.h>
 23
 24 /* Definitions for byte order, according to significance of bytes(高位字節),
 25    from low addresses to high addresses.  The value is what you get by
 26    putting '4' in the most significant byte, '3' in the second most
 27    significant byte, '2' in the second least significant byte, and '1'
 28    in the least significant byte, and then writing down one digit for
 29    each byte, starting with the byte at the lowest address at the left,
 30    and proceeding to the byte with the highest address at the right.  */
 31
 32 #define __LITTLE_ENDIAN 1234
 33 #define __BIG_ENDIAN       4321
 34 #define __PDP_ENDIAN      3412
 35
 36 /* This file defines `__BYTE_ORDER' for the particular machine.  */
 37 #include <bits/endian.h> //前面已經有了_ENDIAN_H 宏的定義,所以這個文件可以包含進來
 38
 39 /* Some machines may need to use a different endianness for floating point
 40    values.  */
 41 #ifndef __FLOAT_WORD_ORDER
 42 # define __FLOAT_WORD_ORDER __BYTE_ORDER
 43 #endif
 44
 45 #ifdef  __USE_BSD
 46 # define LITTLE_ENDIAN  __LITTLE_ENDIAN
 47 # define BIG_ENDIAN __BIG_ENDIAN
 48 # define PDP_ENDIAN __PDP_ENDIAN
 49 # define BYTE_ORDER __BYTE_ORDER
 50 #endif
 51
 52 #if __BYTE_ORDER == __LITTLE_ENDIAN
 53 # define __LONG_LONG_PAIR(HI, LO) LO, HI
 54 #elif __BYTE_ORDER == __BIG_ENDIAN
 55 # define __LONG_LONG_PAIR(HI, LO) HI, LO
 56 #endif
 57
 58
 59 #ifdef __USE_BSD 以下宏定義只對BSD系統有關,其它系統無這些定義
 60 /* Conversion interfaces.  */
 61 # include <bits/byteswap.h>//後面定義的宏需要用到這個文件的宏(如__bswap_16 (x) __bswap_32 (x)等等 )
 62
 63 # if __BYTE_ORDER == __LITTLE_ENDIAN
 64 #  define htobe16(x) __bswap_16 (x)  // htobe16  it means  host to big-endian 16bits
 65 #  define htole16(x) (x)
 66 #  define be16toh(x) __bswap_16 (x)
 67 #  define le16toh(x) (x)
 68
 69 #  define htobe32(x) __bswap_32 (x)
 70 #  define htole32(x) (x)
 71 #  define be32toh(x) __bswap_32 (x)
 72 #  define le32toh(x) (x)
 73
 74 #  define htobe64(x) __bswap_64 (x)
 75 #  define htole64(x) (x)
 76 #  define be64toh(x) __bswap_64 (x)
 77 #  define le64toh(x) (x)
 78 # else
 79 #  define htobe16(x) (x)
 80 #  define htole16(x) __bswap_16 (x)
 81 #  define be16toh(x) (x)
 82 #  define le16toh(x) __bswap_16 (x)
 83
 84 #  define htobe32(x) (x)
 85 #  define htole32(x) __bswap_32 (x)
 86 #  define be32toh(x) (x)
 87 #  define le32toh(x) __bswap_32 (x)
 88
 89 #  define htobe64(x) (x)
 90 #  define htole64(x) __bswap_64 (x)
 91 #  define be64toh(x) (x)
 92 #  define le64toh(x) __bswap_64 (x)
 93 # endif
 94 #endif
 95
 96 #endif  /* endian.h */

////////////////////////////////////////////////////////////////////////////////////
 /usr/include/byteswap.h


 19 #ifndef _BYTESWAP_H
 20 #define _BYTESWAP_H 1
 21
 22 /* Get the machine specific, optimized definitions.  */
 23 #include <bits/byteswap.h>
 24
 25
 26 /* The following definitions must all be macros since otherwise some
 27    of the possible optimizations are not possible.  */
 28
 29 /* Return a value with all bytes in the 16 bit argument swapped.  */
 30 #define bswap_16(x) __bswap_16 (x)  //宏定義中引用了bits/byteswap中的宏
 31
 32 /* Return a value with all bytes in the 32 bit argument swapped.  */
 33 #define bswap_32(x) __bswap_32 (x)
 34
 35 #if defined __GNUC__ && __GNUC__ >= 2
 36 /* Return a value with all bytes in the 64 bit argument swapped.  */
 37 # define bswap_64(x) __bswap_64 (x)
 38 #endif
 39
 40 #endif /* byteswap.h */                              


////////////////////////////////////////////////////////////////////////////////////
/usr/include/bits/byteswap.h文件內容如下:


 /*   Macros to swap the order of bytes in integer values. */
 20
 21 #if !defined _BYTESWAP_H && !defined _NETINET_IN_H && !defined _ENDIAN_H
 22 # error "Never use <bits/byteswap.h> directly; include <byteswap.h> instead."
 23 #endif

 以上語句表明,/usr/include/bits/byteswap.h文件只能包含在/usr/include/byteswap.h以及usr/include/netinet/in.h以及usr/include/endian.h這三個公共對外接口頭文件中。注意宏定義的方式:_NETINET_IN_H 表示netinet文件夾下的in.h文件

外部接口頭文件中。還有以上條件編譯語句形式:defined 宏用來判斷後面的宏是否定義。多個條件可以通過 && 連接。 
 24
 25 #ifndef _BITS_BYTESWAP_H
 26 #define _BITS_BYTESWAP_H 1
 27
 28 /* Swap bytes in 16 bit value.  */
 29 #define __bswap_constant_16(x) /
 30      ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))

/*

 以上爲宏 __bswap_constant_16(x)具體實現,即16位的字節交換

*/


 31
 32 #ifdef __GNUC__ //如果編譯器是GNU gcc 且版本號大於2
 33 # if __GNUC__ >= 2

 34 #  define __bswap_16(x) /
 35      (__extension__                               /
 36       ({ register unsigned short int __v, __x = (x);                  /
 37      if (__builtin_constant_p (__x))                      /
 38        __v = __bswap_constant_16 (__x);                   /
 39      else                                     /
 40        __asm__ ("rorw $8, %w0"                        /
 41             : "=r" (__v)                          /
 42             : "0" (__x)                           /
 43             : "cc");                              /
 44      __v; }))
 45 # else
 46 /* This is better than nothing.  */
 47 #  define __bswap_16(x) /
 48      (__extension__                               /
 49       ({ register unsigned short int __x = (x); __bswap_constant_16 (__x); }))
 50 # endif
 51 #else
 52 static __inline unsigned short int
 53 __bswap_16 (unsigned short int __bsx)
 54 {
 55   return __bswap_constant_16 (__bsx);
 56 }
 57 #endif
 58
 59 /* Swap bytes in 32 bit value.  */
 60 #define __bswap_constant_32(x) /
 61      ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >>  8) |           /
 62       (((x) & 0x0000ff00) <<  8) | (((x) & 0x000000ff) << 24))
 63

134 #endif
135
136 #endif /* _BITS_BYTESWAP_H */

 

 

以上文件內容,基本上實現了字節序轉換的所有的宏(注意沒有用函數實現,而是通過宏替代函數的作用),下面我們來看看具體的/usr/include/netinet/in.h文件:

/* Get system-specific definitions.  */
356 #include <bits/in.h>

357
358 /* Functions to convert between host and network byte order.
359
360    Please note that these functions normally take `unsigned long int' or
361    `unsigned short int' values as arguments and also return them.  But
362    this was a short-sighted decision since on different systems the types
363    may have different representations but the values are always the same.  */
364
365 extern uint32_t ntohl (uint32_t __netlong) __THROW __attribute__ ((__const__));
366 extern uint16_t ntohs (uint16_t __netshort)
367      __THROW __attribute__ ((__const__));
368 extern uint32_t htonl (uint32_t __hostlong)
369      __THROW __attribute__ ((__const__));
370 extern uint16_t htons (uint16_t __hostshort)
371      __THROW __attribute__ ((__const__));
372
373 #include <endian.h>
374
375 /* Get machine dependent optimized versions of byte swapping functions.  */
376 #include <bits/byteswap.h>
377
378 #ifdef __OPTIMIZE__
379 /* We can optimize calls to the conversion functions.  Either nothing has
380    to be done or we are using directly the byte-swapping functions which
381    often can be inlined.  */
382 # if __BYTE_ORDER == __BIG_ENDIAN
383 /* The host byte order is the same as network byte order,
384    so these functions are all just identity.  */
385 # define ntohl(x)   (x)
386 # define ntohs(x)   (x)
387 # define htonl(x)   (x)
388 # define htons(x)   (x)
389 # else
390 #  if __BYTE_ORDER == __LITTLE_ENDIAN
391 #   define ntohl(x) __bswap_32 (x)
392 #   define ntohs(x) __bswap_16 (x)
393 #   define htonl(x) __bswap_32 (x)
394 #   define htons(x) __bswap_16 (x)

395 #  endif
396 # endif
397 #endif

 

可以看到主機到網絡字節序的轉換全部在該文件中實現了。

 

 

 

 

 

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