Conversion between byte array and short, int, float, double and other types

First, get short, int, long, float, double and other data from the byte array in C ++

When performing Modbus protocol communication and network programming, sometimes you need to convert the data received from the serial port or network from the byte array to the corresponding int, float, double and other data, and sometimes you need to consider the big endian byte order and Swap , Found that in C ++ you need to write related conversion functions yourself, so / wrote a function to get the specified type of data from the input byte array, currently supports int16, int32, int64, float, double, the corresponding code is as follows :

#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

main.cpp test code

#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;
}

Second, the conversion between byte arrays and basic data types in C #

The conversion between byte arrays and short, int, float, double, etc. in C # provides a very convenient class BitConverter,
as described in the official Microsoft document: BitConverter Class: Converts base data types to an array of bytes, and an array of bytes to base data types.
That is to say, the BitConverter class converts byte arrays and basic data types to each other.
First, the BitCoverter class has an IsLittleEndian attribute that is used to determine whether the computer's architecture is big-endian or little-endian. The concept of big-endian is common in embedded programming, network programming, and serial port programming. In addition, the byte data type is directly provided in C #, similar to the unsigned char in C and C ++

type of data method
bool ToBoolean(Byte[], Int32)
char ToChar (Byte [], Int32)
double ToDouble(Byte[], Int32)
short ToInt16(Byte[], Int32)
int ToInt32(Byte[], Int32)
long ToInt64(Byte[], Int32)
float ToSingle(Byte[], Int32)
ushort ToUInt16(Byte[], Int32)
uint ToUInt32(Byte[], Int32)
ulong ToUInt64(Byte[], Int32)

The official provides a simple example program, the code is as follows:

// 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
*/

After testing, my Thinkpad computer is little-endian byte order. For
converting a byte array to an int in C # , you can refer to How to convert a byte array to an int (C # Programming Guide) . The corresponding test code is as follows:

1. Example1

This example initializes a byte array, if the computer architecture is little-endian byte order (ie, the least significant byte is stored first), then reverse the array, and then call the ToInt32 (Byte [], Int32) method to convert byte. Convert the array to an int. The second parameter of ToInt32 (Byte [], Int32) specifies the starting index of the byte array.
Note: The output will vary according to your computer's architecture.

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.Example2

In this example, use the GetBytes (int32) method of the BitConvert class to convert an int into a byte array.
Note: The result will vary depending on the size of your computer's architecture.
code show as below:

byte[] bytes = BitConverter.GetBytes(201805978);
Console.WriteLine("byte array: " + BitConverter.ToString(bytes));
// Output: byte array: 9A-50-07-0C

The complete C # code is as follows:

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
        }
    }
}

References

Published 131 original articles · Like 38 · Visit 990,000+

Guess you like

Origin blog.csdn.net/ccf19881030/article/details/104911459