Primero, obtenga datos cortos, int, largos, flotantes, dobles y otros de la matriz de bytes en C ++
Al realizar la comunicación del protocolo Modbus y la programación de la red, a veces necesita convertir los datos recibidos desde el puerto serie o la red desde la matriz de bytes a los datos int, float, double y otros correspondientes, y a veces necesita considerar el orden de bytes de Big Endian y Swap Encontró que en C ++ necesita escribir las funciones de conversión relacionadas usted mismo, por lo que escribí una función para obtener el tipo de datos especificado de la matriz de bytes de entrada, actualmente admite int16, int32, int64, float, double, el código correspondiente es el siguiente :
#ifndef _BYTECONVERTTOOLS_H
#define _BYTECONVERTTOOLS_H
#include <algorithm>
#include <array>
#include <regex> // for std::regex_match
#include <iostream>
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 <string.h>
// 数组
#include <string>
#include <vector>
typedef std::string String;
typedef std::vector<uint8> Uint8Array;
typedef std::vector<uint16> Uint16Array;
typedef std::vector<uint32> Uint32Array;
typedef std::vector<uint64> Uint64Array;
typedef std::vector<int8> Int8Array;
typedef std::vector<int16> Int16Array;
typedef std::vector<int32> Int32Array;
typedef std::vector<int64> Int64Array;
typedef std::vector<float> Float32Array;
typedef std::vector<double> Float64Array;
typedef std::vector<std::string> StringArray;
typedef std::vector<Uint8Array> Uint8sArray;
namespace ByteConvertTools
{
// 输入的byte数组中获取指定类型的数据
// 支持int16,int32,int64,float,double
template<typename T>
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<typename T>
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 <typename T>
void swapBytes(T& var)
{
static_assert(std::is_pod<T>::value, "Type must be POD type for safety");
std::array<char, sizeof(T)> varArray;
std::memcpy(varArray.data(), &var, sizeof(T));
for (int i = 0; i < static_cast<int>(sizeof(var) / 2); i++)
std::swap(varArray[sizeof(var) - 1 - i], varArray[i]);
std::memcpy(&var, varArray.data(), sizeof(T));
}
// 将int16,int32,int64,float,double等转换成16进制字节数组
template<typename T>
bool convertToBytesArray(Uint8Array& _return, const T value, bool isLittle, bool isSwapByte)
{
uint32 byteNum = sizeof(T);
// 将T类型(int16,int32,int64,float,double等)的内容拷贝至tmp8中
Uint8Array tmp8(byteNum);
Uint16Array tmp16(byteNum / 2);
bool isLocalMachineLittleEndian = isLittleEndian();
if (isLittle == isLocalMachineLittleEndian) // 如果是小端
{
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
código de prueba main.cpp
#include <iostream>
#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 << "f1=" << f1 << std::endl;
// f1: 3.14
// 大端数据 + 大端传输
// transfer 40 48 F5 C3
// convert C3 F5 48 40
float f2;
uint8 bytesArr2[4] = { 0x40, 0x48, 0xF5, 0xC3 };
ByteConvertTools::get_data(f2, bytesArr2, 4, 0, false, false);
std::cout << "f2=" << f2 << std::endl;
// f2 : 3.14
// 大端Swap
// 传输: 48 40 C3 F5 uint8[]
float f3;
uint8 bytesArr3[4] = { 0x48, 0x40, 0xC3, 0xF5 };
ByteConvertTools::get_data(f3, bytesArr3, 4, 0, false, true);
std::cout << "f3=" << f3 << std::endl;
// f3: 3.14
/*小端swap
传输 F5 C3 40 48
convert1 48 40 c3 f5
0x4048 0xf5c3
0xf5c3 0x4048*/
float f4;
uint8 bytesArr4[4] = { 0xF5, 0xC3, 0x40, 0x48 };
ByteConvertTools::get_data(f4, bytesArr4, 4, 0, true, true);
std::cout << "f4=" << f4 << std::endl;
// f4: 3.14
return 0;
}
Segundo, la conversión entre matrices de bytes y tipos de datos básicos en C #
La conversión entre matrices de bytes y short, int, float, double, etc. en C # proporciona una clase muy conveniente de BitConverter,
como se describe en el documento oficial de Microsoft: Clase BitConverter: Convierte los tipos de datos base en una matriz de bytes, y una matriz de bytes para tipos de datos base,
es decir, la clase BitConverter convierte matrices de bytes y tipos de datos básicos entre sí.
Primero, la clase BitCoverter tiene un atributo IsLittleEndian que se usa para determinar si la arquitectura de la computadora es big-endian o little-endian. El concepto de big-endian es común en la programación integrada, la programación de red y la programación de puerto serie. Además, el tipo de datos de bytes se proporciona directamente en C #, similar al carácter sin signo en C y C ++
Tipo de datos | Método |
---|---|
bool | ToBoolean (Byte [], Int32) |
carbonizarse | ToChar (Byte [], Int32) |
doble | ToDouble (Byte [], Int32) |
corto | ToInt16 (Byte [], Int32) |
En t | ToInt32 (Byte [], Int32) |
largo | ToInt64 (Byte [], Int32) |
flotador | ToSingle (Byte [], Int32) |
ushort | ToUInt16 (Byte [], Int32) |
Uint | ToUInt32 (Byte [], Int32) |
ulong | ToUInt64 (Byte [], Int32) |
El funcionario proporciona un programa de ejemplo simple, el código es el siguiente:
// Example of the BitConverter.IsLittleEndian field.
using System;
class LittleEndDemo
{
public static void Main( )
{
Console.WriteLine(
"This example of the BitConverter.IsLittleEndian field " +
"generates \nthe following output when run on " +
"x86-class computers.\n");
Console.WriteLine( "IsLittleEndian: {0}",
BitConverter.IsLittleEndian );
}
}
/*
This example of the BitConverter.IsLittleEndian field generates
the following output when run on x86-class computers.
IsLittleEndian: True
*/
Después de la prueba, mi computadora Thinkpad está en orden de bytes little endian. Para
convertir una matriz de bytes en un int en C # , puede consultar Cómo convertir una matriz de bytes en un int (Guía de programación de C #) . El código de prueba correspondiente es el siguiente:
1. Ejemplo1
Este ejemplo inicializa una matriz de bytes, si la arquitectura de la computadora es de orden de bytes little endian (es decir, el byte menos significativo se almacena primero), luego invierte la matriz y luego llama al método ToInt32 (Byte [], Int32) para convertir los cuatro Bytes Convierta la matriz a un int. El segundo parámetro de ToInt32 (Byte [], Int32) especifica el índice inicial de la matriz de bytes.
Nota: La salida variará según la arquitectura de su computadora.
byte[] bytes = { 0, 0, 0, 25 };
// If the system architecture is little-endian (that is, little end first),
// reverse the byte array.
if (BitConverter.IsLittleEndian)
Array.Reverse(bytes);
int i = BitConverter.ToInt32(bytes, 0);
Console.WriteLine("int: {0}", i);
// Output: int: 25
2.Ejemplo2
En este ejemplo, use el método GetBytes (int32) de la clase BitConvert para convertir un int en una matriz de bytes.
Nota: El resultado variará dependiendo del tamaño de la arquitectura de su computadora.
El código es el siguiente:
byte[] bytes = BitConverter.GetBytes(201805978);
Console.WriteLine("byte array: " + BitConverter.ToString(bytes));
// Output: byte array: 9A-50-07-0C
El código completo de C # es el siguiente:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ByteArrayConvertConsoleApp
{
class Program
{
static void Main(string[] args)
{
// Example1: 将字节数组转换成int
/*
This example initializes an array of bytes, reverses the array if the computer architecture is little-endian (that is, the least significant byte is stored first), and then calls the ToInt32(Byte[], Int32) method to convert four bytes in the array to an int. The second argument to ToInt32(Byte[], Int32) specifies the start index of the array of bytes.
*/
// 字节数组转换成int
byte[] bytes = { 0, 0, 0, 25 };
// If the system architecture is little-endian (that is, little end first), reverse the byte array.
// 如果系统体系结构为小端(即小端优先),则反转字节数组。
if (BitConverter.IsLittleEndian)
{
Array.Reverse(bytes);
}
int i = BitConverter.ToInt32(bytes, 0);
Console.WriteLine("int: {0}", i);
// OutPut: int: 25
// Example2: 将int转换成字节数组
byte[] bytes2 = BitConverter.GetBytes(201805978);
Console.WriteLine("bytes array:" + BitConverter.ToString(bytes2));
// OutPut: byte array: 9A-50-07-0C
// Example3: 将float转换成字节数组
float f1 = 3.14f;
byte[] bytes3 = BitConverter.GetBytes(f1);
Console.WriteLine("float {0} convert to bytes array,result is:" + BitConverter.ToString(bytes3));
// OutPut: byte array: C3-F5-48-40
// Example4: 将4个字节的字节数组转换成float
byte[] bytes4 = { 0xC3, 0xF5, 0x48, 0x40 };
// 如果系统体系结构为小端(即小端优先),则反转字节数组。
if (BitConverter.IsLittleEndian)
{
Array.Reverse(bytes4);
}
float f2_result = BitConverter.ToSingle(bytes4, 0);
Console.WriteLine("4 bytes array convert to float, f2_result: {0}", f2_result);
// OutPut: 4 bytes array convert to float, f2_result: -490.5645
byte[] bytes5 = { 0x40, 0x48, 0xF5, 0xC3 };
// 如果系统体系结构为小端(即小端优先),则反转字节数组。
if (BitConverter.IsLittleEndian)
{
// 经过测试,本台机器为小端结构
// 对字节数组bytes5进行反转后,变为{0xC3, 0xF5, 0x48, 0x40}
Array.Reverse(bytes5);
}
float f2_result2 = BitConverter.ToSingle(bytes5, 0);
Console.WriteLine("4 bytes array convert to float, f2_result2: {0}", f2_result2);
// OutPut: 4 bytes array convert to float, f2_result2: 3.14
}
}
}
Referencias
- ¿Cómo convierto entre valores big-endian y little-endian en C ++?
- ¿Cómo convertir una matriz de bytes en doble en C?
- La forma más rápida de convertir 4 bytes para flotar en c ++
- Intercambio de endianness sin ntohs
- Endianness: orden de bytes de Endian grande y pequeña
- c ++ Use expresiones regulares para juzgar los valores numéricos (incluidos números negativos, decimales y enteros) en la cadena coincidente
- Cómo convertir una matriz de bytes a un int (Guía de programación de C #)
- BitConverter.IsLittleEndian Field- C #
- BitConverter Clase-C #