一、在C++中从字节数组中获取short,int,long,float,double等数据
在进行Modbus协议通信和网络编程时,有时需要将从串口或者网络中接收的数据从字节数组转换成对应的int,float,double等数据,有时还要考虑大小端字节序以及Swap的问题,发现在C++中需要自己写相关的转换函数,于是/写了一个函数,用于从输入的byte数组中获取指定类型的数据,目前支持int16,int32,int64,float,double,对应的代码如下:
#ifndef _BYTECONVERTTOOLS_H
#define _BYTECONVERTTOOLS_H
#include
#include
#include // for std::regex_match
#include
using namespace std;
// 自定义
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
#ifdef WIN32
typedef unsigned __int64 uint64;
typedef __int64 int64;
#else
typedef unsigned long long uint64;
typedef long long int64;
#endif
typedef char int8;
typedef short int16;
typedef int int32;
#include
// 数组
#include
#include
typedef std::string String;
typedef std::vector Uint8Array;
typedef std::vector Uint16Array;
typedef std::vector Uint32Array;
typedef std::vector Uint64Array;
typedef std::vector Int8Array;
typedef std::vector Int16Array;
typedef std::vector Int32Array;
typedef std::vector Int64Array;
typedef std::vector Float32Array;
typedef std::vector Float64Array;
typedef std::vector StringArray;
typedef std::vector Uint8sArray;
namespace ByteConvertTools
{
// 输入的byte数组中获取指定类型的数据
// 支持int16,int32,int64,float,double
template
bool get_data(T& _return, const uint8* buffer, size_t buffersize,
uint16 offset_bytes, bool isLittle, bool isSwapByte)
{
uint32 totalByteNum = buffersize;
uint32 byteNum = sizeof(T);
uint32 regNum = byteNum / 2;
uint32 startPos = offset_bytes;
uint32 endPos = startPos + byteNum;
if ((regNum == 0 || byteNum % 2 != 0) || (startPos > totalByteNum || endPos > totalByteNum)) {
return false;
}
// 获取模板参数T的具体类型(int16,int32,int64,float,double)
auto& type = typeid(T);
if ((type == typeid(double) || type == typeid(int64) || type == typeid(uint64)) ||
(type == typeid(float) || type == typeid(uint32) || type == typeid(int32)) ||
(type == typeid(int16) || type == typeid(uint16))) {
Uint8Array tmp8; Uint16Array tmp16(regNum);
/*
不同的计算机体系结构使用不同的字节顺序存储数据。
“大端”表示最高有效字节在单词的左端。即最高位字节存放在字节数组的低位
“小端”表示最高有效字节在单词的右端。即最高位字节存放在字节数组的高位
*/
if (isLittle) {
// 小端字节序 dcba
std::copy(buffer + startPos, buffer + endPos, std::back_inserter(tmp8));
}
else {
// 大端字节序,则将字节数组进行反转 abcd
std::reverse_copy(buffer + startPos, buffer + endPos, std::back_inserter(tmp8));
}
memcpy(tmp16.data(), tmp8.data(), byteNum);
if (isSwapByte)
{
std::reverse(tmp16.begin(), tmp16.end());
Uint8Array tmp1(byteNum);
memcpy(tmp1.data(), tmp16.data(), byteNum);
std::reverse(tmp1.begin(), tmp1.end());
memcpy(tmp16.data(), tmp1.data(), byteNum);
}
memcpy(&_return, tmp16.data(), byteNum);
return true;
}
return false;
}
template
bool get_data(T& _return, const Uint8Array& buffer,
uint16 offset_bytes, bool isLittle, bool isSwapByte)
{
return get_data(_return, buffer.data(), buffer.size(), offset_bytes, isLittle, isSwapByte);
}
// 判断本台机器是大端字节序还是小端字节序
bool isLittleEndian()
{
int iData = 1;
char *p = (char*)&iData;
if (*p == 1)
{
return true;
}
else {
return false;
}
}
template
void swapBytes(T& var)
{
static_assert(std::is_pod::value, "Type must be POD type for safety");
std::array varArray;
std::memcpy(varArray.data(), &var, sizeof(T));
for (int i = 0; i
memcpy(tmp8.data(), &value, byteNum);
}
else {
memcpy(tmp8.data(), &value, byteNum);
// 将小端字节序转换成大端字节序或者将大端字节序转换成小端字节序
std::reverse(tmp8.begin(), tmp8.end());
}
// 交换相邻的两个字节
memcpy(tmp16.data(), tmp8.data(), byteNum);
if (isSwapByte)
{
std::reverse(tmp16.begin(), tmp16.end());
Uint8Array tmp1(byteNum);
memcpy(tmp1.data(), tmp16.data(), byteNum);
std::reverse(tmp1.begin(), tmp1.end());
memcpy(tmp16.data(), tmp1.data(), byteNum);
}
memcpy(tmp8.data(), tmp16.data(), byteNum);
_return = tmp8;
return true;
}
// c++用正则表达式判断匹配字符串中的数字数值(包括负数,小数,整数)MFC编辑框判断数值
static bool isStrNumber(String strInput)
{
//正则匹配数值包括负数 小数 整数
std::string strPattern{ "-[0-9]+(.[0-9]+)?|[0-9]+(.[0-9]+)?" };
std::regex re(strPattern);
bool retMatchStr = false;
retMatchStr = std::regex_match(strInput, re);
return retMatchStr;
}
};
#endif
main.cpp测试代码
#include
#include "ByteConvertTools.h"
int main(int argc, char* argv[])
{
/* 数据转换
float 3.14
mem 0xF5C3 0x4048
mem C3 F5 48 40
大端数据 + 大端传输
transfer 40 48 F5 C3
convert 1 C3 F5 48 40
小端数据
传输 C3 F5 48 40
大端swap
传输 48 40 C3 F5 uint8[]
convert 1 0x4048 0xF5C3 uint16[]
0xF5C3 0x4048
C3 F5 48 40 UINT8[]
小端swap
传输 F5 C3 40 48
convert1 48 40 c3 f5
0x4048 0xf5c3
0xf5c3 0x4048
*/
/*
不同的计算机体系结构使用不同的字节顺序存储数据。
“大端”表示最高有效字节在单词的左端。
“小端”表示最高有效字节在单词的右端。
*/
//数据转换
//float 3.14
//mem 0xF5C3 0x4048
//mem C3 F5 48 40
// 小端数据
// 传输: C3 F5 48 40
float f1;
uint8 bytesArr1[4] = { 0xC3, 0xF5, 0x48, 0x40 };
ByteConvertTools::get_data(f1, bytesArr1, 4, 0, true, false);
std::cout 0x48, 0x40, 0xC3, 0xF5 };
ByteConvertTools::get_data(f3, bytesArr3, 4, 0, false, true);
std::cout |