1. 位元組順序概念
位元組順序是指占記憶體多於一個位元組類型的資料在記憶體中的存放順序,通常有小端、大端兩種位元組順序。
大端對齊:記憶體的低地址位存放著高位元據;
小端對齊:記憶體的低地址位存放著低位元據;
舉個例子,記憶體中兩個連續位元組中的資料為0x12 0x34,表示一個short,如果是大端對齊,這個數為0x1234;如果是小端對齊,則這個數為0x3412。
2. 測試
在我的開發機器上(linux2.6.16)上,經過測試,為小端對齊,轉化為網路位元組序之後,為大端對齊。
測試程式很簡單:
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <arpa/inet.h>int main(){ int16_t x = 1; if(*(char*)&x == 1) printf("little endian\n"); else printf("big endian\n"); int16_t y = ntohs(x); if(*(char*)&y == 1) printf("net little endian\n"); else printf("net big endian\n");}
3. linux api介面
網路位元組序與本地位元組序的轉化,glibc提供了4個介面,man的結果如下:
BYTEORDER(3) Linux Programmer's Manual BYTEORDER(3)NAME htonl, htons, ntohl, ntohs - convert values between host and network byte orderSYNOPSIS #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);DESCRIPTION The htonl() function converts the unsigned integer hostlong from host byte order to network byte order. The htons() function converts the unsigned short integer hostshort from host byte order to network byte order. The ntohl() function converts the unsigned integer netlong from network byte order to host byte order. The ntohs() function converts the unsigned short integer netshort from network byte order to host byte order. On the i386 the host byte order is Least Significant Bytefirst, whereasthe network byte order, as used on the Internet, is Most Sig- nificant Byte first.
Glibc還提供了一組介面,直接轉化本地位元組序到大端或者小端對齊。(man查看的結果是glibc2.9之後開始支援的,我這邊的機器上還沒有)
ENDIAN(3) Linux Programmer's Manual ENDIAN(3)NAME htobe16, htole16, be16toh, le16toh, htobe32, htole32, be32toh, le32toh, htobe64, htole64, be64toh, le64toh - convert values between host and big-/little-endian byte orderSYNOPSIS #define _BSD_SOURCE /* See feature_test_macros(7) */ #include <endian.h> uint16_t htobe16(uint16_t host_16bits); uint16_t htole16(uint16_t host_16bits); uint16_t be16toh(uint16_t big_endian_16bits); uint16_t le16toh(uint16_t little_endian_16bits); uint32_t htobe32(uint32_t host_32bits); uint32_t htole32(uint32_t host_32bits); uint32_t be32toh(uint32_t big_endian_32bits); uint32_t le32toh(uint32_t little_endian_32bits); uint64_t htobe64(uint64_t host_64bits); uint64_t htole64(uint64_t host_64bits); uint64_t be64toh(uint64_t big_endian_64bits); uint64_t le64toh(uint64_t little_endian_64bits);
4. 64位整型,本地與網路位元組序的轉化
如果是int64_t或者uint64_t,沒有ntoh系列介面支援,只能通過htobe64這種介面來實現本地位元組序到網路位元組序的轉換(從2中的測試中,可以得到網路位元組序為大端對齊)。
如果glibc的版本不支援htobe系列的介面,那麼只能自己寫轉換程式了,一個簡單的轉換程式如下:
uint64_t htonll(uint64_t v) { union { uint32_t lv[2]; uint64_t llv; } u; u.lv[0] = htonl(v >> 32); u.lv[1] = htonl(v & 0xFFFFFFFFULL); return u.llv;}uint64_t ntohll(uint64_t v) { union { uint32_t lv[2]; uint64_t llv; } u; u.llv = v; return ((uint64_t)ntohl(u.lv[0]) << 32) | (uint64_t)ntohl(u.lv[1]);}
5. 參考文章
http://stackoverflow.com/questions/809902/64-bit-ntohl-in-c
http://cpp.ezbty.org/import_doc/linux_manpage/be64toh.3.html
http://www.unix.com/man-page/Linux/3/ntohl/