Conversión entre byte array y short, int, float, double y otros tipos

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

131 artículos originales publicados · Me gusta 38 · Visita 990,000+

Supongo que te gusta

Origin blog.csdn.net/ccf19881030/article/details/104911459
Recomendado
Clasificación