#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)是顛倒的,局部順序(字節內部)是一致的、不變的。
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)是顛倒的,局部順序(字節內部)是一致的、不變的。
- /**
- * @file Code_Convert.h
- * @brief
- * @author Donhao
- * @date 2010-7-17 12:33:16
- * @version
- * <pre><b>copyright: </b></pre>
- * <pre><b>All rights reserved.</b></pre>
- * <pre><b>modification:</b></pre>
- * <pre>Write modifications here.</pre>
- */
- #ifndef _CODE_CONVERT_H
- #define _CODE_CONVERT_H
- /**
- * @defgroup 主機字節序與網絡字節序之間的轉換
- * @brief
- *
- * Detailed description.
- * @{
- */
- /**
- * @brief Code_Is_Net
- *
- * 判斷本機是主機字節序還是網絡字節序.
- * @return BOOL
- */
- BOOL Code_Is_Net(void);
- /**
- * @brief Code_H2N16
- *
- * @param[in] x
- * @return unsigned short
- */
- unsigned short Code_H2N16(unsigned short x);
- /**
- * @brief Code_H2N32
- *
- * @param[in] x
- * @return unsigned long
- */
- unsigned long Code_H2N32(unsigned long x);
- /** @} */
- #endif
- /**
- * @file Code_Convert.c
- * @brief
- * @author Donhao
- * @date 2010-7-17 12:33:31
- * @version
- * <pre><b>All rights reserved.</b></pre>
- * <pre><b>modification:</b></pre>
- * <pre>Write modifications here.</pre>
- */
- #include "Code_Convert.h"
- BOOL Code_Is_Net(void)
- {
- unsigned short value = 0x55AA;
- if (0x55 == *((unsigned char*)(&value)))
- {
- return TRUE;
- }
- else
- {
- return FALSE;
- }
- }
- unsigned short Code_H2N16(unsigned short x)
- {
- unsigned short y = 0;
- unsigned short z = 0;
- z = x & 0x00FF;
- y = z << 8;
- z = x & 0xFF00;
- y += (z >> 8);
- return y;
- }
- unsigned long Code_H2N32(unsigned long x)
- {
- unsigned long y = 0;
- unsigned long z = 0;
- z = x & 0x000000FF;
- y = z << 24;
- z = x & 0x0000FF00;
- y += (z << 8);
- z = x & 0x00FF0000;
- y += (z >> 8);
- z = x & 0xFF000000;
- y += (z >> 24);
- return y;
- }
通過對大小端的存儲原理分析可發現,對於 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)
main()
{
}
字節序轉換:
ntohs(n) = __swab16(n),
ntohl = __swab32(n)。
__swab16與__swab32函數定義如下所示。
#define ___swab16(x)
{
}
#define ___swab32(x)
{
}
寫法很嚴謹。簡化版的:
#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
#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