字节序(byte order)关系到多字节整数(short/int16、int/int32,int64)和浮点数的各字节在内存中的存放顺序。字节序分为两种:小端字节序(little endian)和大端字节序(big endian)。小端字节序:低字节存放在内存低地址,例如对两字节整数0x0100(十进制数256),低字节00放在低地址(假设地址为0x0041f880),高字节01放在高地址0x0041f881。大端字节序:高字节在低地址,同样是0x0100,高字节01放在低地址(假设地址为0x0041f880),低字节00放高地址0x0041f881。可见对相同的两字节整数,在不同字节序的机器上其内存布局是不同的,反过来内存布局相同的,在不同字节序的机器上被解释为不同的整数值,除非这几个字节值相同。
字节序是由cpu处理器架构决定的,和操作系统无关,例如Intel cpu采用小端字节序,PowerPC采用大端字节序,有些cpu例如Alpha支持两种字节序,但在使用时要设置具体采用哪一种字节序,不可能同时用两种。主机字节序(host byte order)就是指当前机器的字节序,根据cpu处理器的架构和设置,主机字节序可为小端字节序或大端字节序。关于字节序问题,较全面的描述见https://en.wikipedia.org/wiki/Endianness。
在socket网络编程中通常会涉及到多字节整数、浮点数的传输,如果两台机器字节序不同,直接传多字节整数或浮点数会导致双方将这些多字节解释成不同的数字,所以要在网络协议中规定编解码方式,例如有的协议将整数编码成字符串来避免字节序问题,但只要协议中有多字节整数,都要规定采用什么字节序来表示协议中的多字节整数(除非能保证两台机器的字节序是相同的),也就出现了网络字节序,网络字节序其实就是大端字节序,协议当然也可采用小端字节序,只要双方统一就行。
如上所述,在设计网络二进制协议时,对多字节整数,要规定打包传输时的字节序:网络字节序还是小端字节序。客户端和服务器代码在打包和解包时,对多字节整数,要进行主机字节序和协议规定的字节序的相互转化。
Java应用通常使用java.nio.ByteBuffer进行协议数据的打包和解包,其order(ByteOrder bo)方法可设置打包或解包使用的字节序;如果使用netty框架,可使用ByteBuf类的order方法。
C/C++应用通常使用C库中的如下函数来进行主机字节序和网络字节序的相互转换。
// hton* 主机字节转网络字节序
uint64_t htonll(uint64_t hostlonglong);
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
// ntoh* 网络字节序转主机字节序
uint64_t ntohll(uint64_t hostlonglong);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
linux系统在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);
htobe*(例如htobe16)表示主机字节序到大端字节序(网络字节序);htole*表示主机字节序到小端字节序;be*toh表示大端到主机;le*toh表示小端到主机。
上面的字节序转换函数有个缺点,就是方法太多不方便使用,需要根据多字节整数的类型(uint16_t/int16_t/uint32_t/int32_t/uint64_t/int64_t)来调用不同的转换函数,所以在c++应用中利用模板技术编写了4个统一的字节序转换函数,和整数的类型无关。如下:
/*
* ByteOrderUtil.h
*
* Created on: Nov 15, 20xx
* Author: wanshi
*/
#ifndef BYTEORDERUTIL_H_
#define BYTEORDERUTIL_H_
#include <stdint.h>
namespace ByteOrder {
const uint16_t us_flag = 1;
// little_end_flag 表示主机字节序是否小端字节序
const bool little_end_flag = *((uint8_t*)&us_flag) == 1;
//小端到主机
template<typename T> T le_to_host(T& from)
{
T to;
uint8_t byteLen = sizeof(T);
if(little_end_flag){
return from;
}
else{
char* to_char = (char*)&to;
char* from_char = (char*)&from;
for(int i=0;i<byteLen;i++){
to_char[i] = from_char[byteLen-i-1];
//此处也可用移位操作来实现
}
return to;
}
}
//主机到小端
template<typename T> T host_to_le(T& from)
{
return le_to_host(from);
}
//大端到主机
template<typename T> T be_to_host(T& from)
{
T to;
uint8_t byteLen = sizeof(T);
if(!little_end_flag){
return from;
}
else{
char* to_char = (char*)&to;
char* from_char = (char*)&from;
for(int i=0;i<byteLen;i++){
to_char[i] = from_char[byteLen-i-1];
//此处也可用移位操作来实现
}
return to;
}
}
//主机到大端
template<typename T> T host_to_be(T& from)
{
return be_to_host(from);
}
}
#endif /* BYTEORDERUTIL_H_ */
使用演示:
#include "ByteOrderUtil.h"
using namespace ByteOrder;
int main(int argc,char** argv)
{
uint16_t u16t = 0x1514;
//host到小端
uint16_t leu16t = host_to_le(u16t);
uint16_t hu16t = le_to_host(leu16t);
uint64_t u64t = 0x15141312;
//host到大端
uint64_t beu64t = host_to_be(u64t);
uint64_t hu64t = be_to_host(beu64t);
return 0;
}
相关推荐
该程序将 BMP/TIFF/JPG/PNG 文件转换为嵌入的 C/C++ 字节数组。 当您想在显示器上显示单色图像时,这非常有用。 它在数据数组生成之前将您的图像转换为单色。 源图像中较暗的颜色将产生“开”像素,而较亮的颜色将...
本篇文章着重介绍使用c++和python语言,如何实现主机字节序和网络字节序的相互转换。首先回顾一下主机字节序和网络字节序的概念: 主机字节序是自己的主机内部,内存中数据的处理方式,要么是大端,要么是小端,...
用于C/C++的繁简转头文件,可以迅速定位转换。 //*****************************说明****************************** //==========================AllCode[][]数组======================== //繁简转换编码对照数组...
提供一个大小端转换的类,可以转换short int float double类型,提供一个大小端转换的类,可以转换short int float double类型,提供一个大小端转换的类,可以转换short int float double类型
开发过程中的一些实用工具函数源码:获得当前程序的路径、获得ini文件内容、设置ini文件内容、获得ini的节点名称、校验文件/路径是否存在、创建路径、获得/写入文件内容/遍历文件夹、字符串转换、文件复制、字符编码...
用C/C++语言写一函数完成该算法,给出复杂度 <br>6.对序列1、1、2、3、5、8、13。。。。 是Fab..数列 2、3、5、13...是Fab..质数数列,因为他们与自己前面的Fab...数列都互质 给出k,返回第k小的...
一开始学习C/C++的时候会以为,这个语言很严谨,在编码上不容许有任何闪失,不然编译肯定不通过。但其实和后续的C#和java等等语言相比,C/C++的规范还是非常非常宽松的。至少在指针类型各种转换中就能体现出来,让...
提供了将 C/C++ 源代码优化地转换为任何8位、16位、32位、64位CPU机器码的接口。<br/>2. 扩展了关键字auto。只需声明,便可完全像调用普通函数一样地调用动态库中的函数。<br/>3. 在执行文件中自动嵌入YC编译器,可...
windows(intel平台):采用小端字节序存储数据【低地址存放数据的低位,高地址存放数据的高位,数据的高位存放在数组的后面】(windows接收java发送过来的short,int需要调用ntohs和ntohl来转换到小数端) 【数据高位】:...
VC++ 将字节转换成KB、MB和GB VC++ 将字节转换成KB、MB和GB
直接使用内存结构相同的实体即可直接读取,adts的头部字段是以bit为单位的,这就给解析其头部带来了一定的难度,几乎获取每个字段都需要进行位操作,一些跨byte的位还需要进行字节序的转换。本文将提供解析adts头的...
一、 基本知识 主机字节序和网络字节序 主机字节序即内存中存储字节的方法有: 1. Little endian:将低序字节存储在起始地址 2. Big endian:将高序...uint32_t ntohl(uint32_t 位的网络字节序>) //转换为主机字节序
多字节与UTF-8、Unicode之间的转换 ,里面有相互转换的6个函数 ,稍微修改下可以加到自己的c++程序中,比较好用
在C/C++中,将浮点数强制转换为整数时,不会采用数学上四舍五人的方式,而是食弃掉小数部分,不会进位。 浮点数的操作不会用到通用寄存器,而是会使用浮点协处理器的浮点寄存器,专门对浮点数进行运算处理。
整个程序转换为byte数组,但是自己也没实际试过,这几天有时间就研究了一下,发现原来操作很简单比起操作资源也来更容易理解, 所以用win32asm做了个示例,同时也在Vc中做了测试,都是一样简单。本来想在VB中也试试...
(2)定义位操作LOAD32H(x, y) 将uint8_t y[4] 转换成 uint32_t x,STORE32H(x, y) 将uint32_t x 转换成 uint8_t y[4],BYTE(x, n) 从uint32_t x中提取从低位开始的第n个字节,MIX(x) 密钥扩展中的SubWord(RotWord...
最近在C++编程中经常遇到需要多字节字符与宽字节字符相互转换的问题,一直自己贴那几句代码。觉得麻烦,于是就自己写了一个类来封装wchar_t与char类型间的转换,其他的,诸如:CString\ LPWSTR\TCHAR CHAR\LPSTR之间...
字节序转换函数 地址转换函数 套接字类型 07socket编程(二) TCP客户/服务器模型 回射客户 /服务器 socket、bind、listen、accept、connect 08socket编程(三) SO_REUSEADDR 处理多客户连接(process-...
16进制与字符串、字节数组之间的转换 16进制与字符串、字节数组之间的转换