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 order
SYNOPSIS
#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 Byte first,
whereas the 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 order
SYNOPSIS
#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