网络字节序转换的操作函数有这几个 ntohs() ,htons() , ntohl() ,htonl() , 不同平台下这几个函数依赖的头文件各有千秋, 而且还没有 64 位的转换接口. 写跨平台代码的时候, 为了省掉这些差异, 干脆自己来实现一套, 这里做个笔记.
1. 知识要点
大端模式 (Big-endian): 是指数据的高字节, 保存在内存的低地址中, 而数据的低字节, 保存在内存的高地址中, 这样的存储模式有点儿类似于把数据当作字符串顺序处理: 地址由小向大增加, 而数据从高位往低位放.
小端模式 (Little-endian): 是指数据的高字节保存在内存的高地址中, 而数据的低字节保存在内在的低地址中, 这种存储模式将地址的高低和数据位 权有效结合起来, 高地址部分权值高, 低地址部分权值低, 和我们的逻辑方法一致.
主机字节序: 是指 整数 (如 16 位, 32 位, 64 位这些类型的整数) 在内存中保存的顺序, 不同的 CPU 可能使用不同的字节序类型, 现下绝大多数使用小端模式.
网络字节序: 网络字节序是使用大端的模式.
2. 判断主机字节序
参看 Linux 内核的源代码, 是类似于这样实现的:
- static union
- {
- x_char_t xct_order[4];
- x_uint32_t xut_order;
- } xhost_order = { { 'L', '?', '?', 'B' } };
- #define X_IS_LITTLE_ENDIAN ('L' == (x_char_t)xhost_order.xut_order)
- #define X_IS_BIG_ENDIAN ('B' == (x_char_t)xhost_order.xut_order)
3. 自己实现的网络字节序转换函数
代码如下所示:
- typedef char x_char_t;
- typedef unsigned short x_uint16_t;
- typedef unsigned int x_uint32_t;
- typedef unsigned long long x_uint64_t;
- /**
- * @brief 用于进行判断主机字节序的联合体.
- * @note
- * 小端: 低地址存放低字节, 高地址存放高字节;
- * 大端: 高地址存放低字节, 低地址存放高字节;
- * 网络字节序是大端.
- */
- static union
- {
- x_char_t xct_order[4];
- x_uint32_t xut_order;
- } xhost_order = { { 'L', '?', '?', 'B' } };
- #define X_IS_LITTLE_ENDIAN ('L' == (x_char_t)xhost_order.xut_order)
- #define X_IS_BIG_ENDIAN ('B' == (x_char_t)xhost_order.xut_order)
- /**********************************************************/
- /**
- * @brief 字节序转换: 16 位整数从 网络字节序 转成 主机字节序.
- */
- x_uint16_t vx_ntohs(x_uint16_t xut_short)
- {
- if (X_IS_LITTLE_ENDIAN)
- return ((xut_short <<8) | (xut_short>> 8));
- return xut_short;
- }
- /**********************************************************/
- /**
- * @brief 字节序转换: 16 位整数从 主机字节序 转成 网络字节序.
- */
- x_uint16_t vx_htons(x_uint16_t xut_short)
- {
- if (X_IS_LITTLE_ENDIAN)
- return ((xut_short <<8) | (xut_short>> 8));
- return xut_short;
- }
- /**********************************************************/
- /**
- * @brief 字节序转换: 32 位整数从 网络字节序 转成 主机字节序.
- */
- x_uint32_t vx_ntohl(x_uint32_t xut_long)
- {
- if (X_IS_LITTLE_ENDIAN)
- return (((xut_long ) <<24) |
- ((xut_long & 0x0000FF00) << 8) |
- ((xut_long & 0x00FF0000)>> 8) |
- ((xut_long )>> 24));
- return xut_long;
- }
- /**********************************************************/
- /**
- * @brief 字节序转换: 32 位整数从 主机字节序 转成 网络字节序.
- */
- x_uint32_t vx_htonl(x_uint32_t xut_long)
- {
- if (X_IS_LITTLE_ENDIAN)
- return (((xut_long ) <<24) |
- ((xut_long & 0x0000FF00) << 8) |
- ((xut_long & 0x00FF0000)>> 8) |
- ((xut_long )>> 24));
- return xut_long;
- }
- /**********************************************************/
- /**
- * @brief 字节序转换: 64 位整数从 网络字节序 转成 主机字节序.
- */
- x_uint64_t vx_ntohll(x_uint64_t xult_llong)
- {
- if (X_IS_LITTLE_ENDIAN)
- return (((xult_llong ) <<56) |
- ((xult_llong & 0x000000000000FF00) << 40) |
- ((xult_llong & 0x0000000000FF0000) << 24) |
- ((xult_llong & 0x00000000FF000000) << 8) |
- ((xult_llong & 0x000000FF00000000)>> 8) |
- ((xult_llong & 0x0000FF0000000000)>> 24) |
- ((xult_llong & 0x00FF000000000000)>> 40) |
- ((xult_llong )>> 56));
- return xult_llong;
- }
来源: http://www.bubuko.com/infodetail-3361302.html