c/c++字节序转换(转)
字节序(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 = ;
// little_end_flag 表示主机字节序是否小端字节序
const bool little_end_flag = *((uint8_t*)&us_flag) == ; //小端到主机
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=;i<byteLen;i++){
to_char[i] = from_char[byteLen-i-];
//此处也可用移位操作来实现
}
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=;i<byteLen;i++){
to_char[i] = from_char[byteLen-i-];
//此处也可用移位操作来实现
}
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 ;
}
转自:https://wanshi.iteye.com/blog/2214693
c/c++字节序转换(转)的更多相关文章
- 套接字编程相关函数(1:套接字地址结构、字节序转换、IP地址转换)
1. 套接字地址结构 1.1 IPv4套接字地址结构 IPv4套接字地址结构通常也称为“网际套接字地址结构”,它以sockaddr_in命名,定义在<netinet/in.h>头文件中.下 ...
- socket编程相关的结构体和字节序转换、IP、PORT转换函数
注意:结构体之间不能直接进行强制转换, 必须先转换成指针类型才可以进行结构体间的类型转换, 这里需要明确的定义就是什么才叫强制转换. 强制转换是将内存中一段代码以另一种不同类型的方式进行解读, 因此转 ...
- 字节序转换与结构体位域(bit field)值的读取 Part 2 - 深入理解字节序和结构体位域存储方式
上一篇文章讲解了带位域的结构体,在从大端机(Big Endian)传输到小端机(Little Endian)后如何解析位域值.下面继续深入详解字节序,以及位域存储的方式. (1) 我们知道,存储数字时 ...
- 字节序转换与结构体位域(bit field)值的读取
最近又遇到了几年前遇到的问题,标记一下. 对于跨字节位域(bit field)而言,如果数据传输前后环境的字节序不同(LE->BE,BE->LE),简单地调用(ntohs/ntohl/ht ...
- c 网络字节序和本机字节序转换
将多字节整数类型的数据,从主机的字节顺序转化为网络字节顺序 #include <netinet/in.h> uint32_t htonl(uint32_t hostlong);uint16 ...
- Linux 网络编程详解一(IP套接字结构体、网络字节序,地址转换函数)
IPv4套接字地址结构 struct sockaddr_in { uint8_t sinlen;(4个字节) sa_family_t sin_family;(4个字节) in_port_t sin_p ...
- 【转】[c/c++ ]字节序与大小端转换--不错
原文网址:http://blog.csdn.net/kuai0705/article/details/20841133 注明: 以下内容均为学习内容整理,记录,便于自己学习,并非完全意义上的自产,如有 ...
- socket套接字(字节序、地址转换)
什么是socket: socket可以看成是用户进程与内核网络协议栈的编程接口. socket不仅可以用于本机的进程间通信,还可以用于网络上 不同主机之间的进程通信.IPv4套接口地址结构 struc ...
- linux网路编程:字节序(大端、小端、网络、主机)
字节序:就是数据在内存中的存放顺序,也可称之为端模式. 大端模式和小端模式的定义 1) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端. 2) Big-End ...
随机推荐
- 给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。
该题还是考杨辉三角计算,只不过最后每一行都放入List集合中,然后返回,直接看代码: public static List<List<Integer>> generate(in ...
- Linux下C语言的文件操作
代码: #include <stdio.h> #include <string.h> #include <fcntl.h> /*************基本的函数A ...
- 用sql的avg(score)求完平均值后,保存两位小数的方法(用于查询或视图)
查jx_score表的平均值,以哪次考试(testid)和科目分组(courseid) select testid, courseid, round(avg(`jx_score`.`score`),2 ...
- fastAdmin进阶
基本知识流程一栏链接 bootstrapTable fastadmin系统配置(符内置规则): fastadmin默认的controller已实现的方法 一张图解析fastadmin的表格: fast ...
- Java大数统计-hdu1316
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1316 题目描述: 给你一个范围,问你在这个范围内有多少斐波拉契数. 代码实现: import java ...
- Jenkins环境搭建(1)-下载与安装
Jenkins简介 Jenkins是一个功能强大的应用程序,允许持续集成和持续交付项目,它是一个免费的源代码,可以处理任何类型的构建或持续集成.集成Jenkins可以用于一些测试和部署技术. Jenk ...
- SpringMVC(十五) RequestMapping map模型数据
控制器中使用map模型数据,传送数据给视图. 控制器参考代码: package com.tiekui.springmvc.handlers; import java.util.Arrays; impo ...
- linux学习笔记 ftp命令
ftp server with sites et up for downloaing files sometimes provides an anonymous ftp account 数据传输 ft ...
- 项目部署相关命令(pm2)
普通方式启动后台服务: nohup npm start & 关闭服务,需要找到进程号: lsof -i :3000 kill -9 进程号 通过pm2启动项目,可实现关闭自启动: 安装pm2: ...
- .net(二)
1.维护数据库的完整性.一致性.你喜欢用触发器还是自写业务逻辑?为什么? 答:尽可能用约束(包括CHECK.主键.唯一键.外键.非空字段)实现,这种方式的效率最好:其次用触发器,这种方式可以保证无论何 ...