Use MFC to write byte transcoding tool, support the conversion between numeric and byte code

I. Introduction

Recently, based on the MFC dialog box, write a byte transcoding gadget (value and byte code conversion, including big and small end and swap form, data includes integer and floating point data). When using serial ports, network communications, and embedded software development, big-endian byte order and Byte Swap are very common things. Many tool software such as Modbus Poll and Modbus Slave provide values ​​(short, unsigned short, int, unsigned int , long long, unsigned long long, float, double and other values) 4 representations: Big-endian (big endian), Little-endian (little endian), Big-endian byte swap, Little-endian byte swap. As shown below, the Display menu of Modbus Poll and Modbus Slave shows this situation:
Modbus Poll
Modbus Slave

Second, endian (Endian), big-endian (Big-Endian), little-endian (Little-Endian)

1. Processor byte order and data representation:

The computer processor stores data in large or small endian format according to the CPU processor architecture. The operating system (OS) does not affect the durability of the system. Big-endian byte order is considered a standard or neutral "network byte order". Big-endian byte ordering is an easy-to-understand format and the order most often displayed by a hexadecimal calculator. The size of common CPU processors is shown in the following table:

processor Big and small
Motorola 68000 Big Endian
PowerPC (PPC) Big Endian
Sun Sparc Big Endian
IBM S/390 Big Endian
Intel x86 (32 bit) Little Endian
Intel x86_64 (64 bit) Little Endian
Dec VAX Little Endian
Alpha Bi (Big / Little) Endian
ARM Bi (Big / Little) Endian
IA-64 (64 bit) Bi (Big / Little) Endian
MIPS Bi (Big / Little) Endian

Big-endian byte order hardware stores their most significant byte (MSB) and least significant byte (LSB) in reverse order from each other. Therefore, data exchange between large and small byte order systems (including conversion to network byte order byte order) usually requires byte order data to achieve byte order conversion. This only applies to binary data values, not to text strings.

2. Byte order and data representation in memory:

Big-endian byte order refers to the order in which the most significant byte comes first. This means that the byte representing the largest value is ranked first. Positive integers are printed in this way. The number "1025" represents the first number representing "1000". This is the most comfortable expression of humanity. The most significant value is first expressed in bytes to represent computer memory. The number 1025 is represented as 0x0401 in hexadecimal, where 0x0400 represents 1024 and 0x0001 represents the number 1. The sum is 1025. In this big-endian byte order number representation, the most significant (larger value) byte is listed first, that is, the high-order byte is placed in the low-order address.
As you can see, word length is a factor that determines how many bytes are used to represent numbers. Endian byte order affects integer and floating-point data, but does not affect strings, because they maintain the string order that programmers view and expect.

Decimal: 1025
  • 16 bit representation in memory:
    • Big Endian:
      Hex: 0x0401
      binary: 00000100 00000001
      • Little Endian:
        Hex: 0x0104
        binary: 00000001 00000100
  • 32 bit representation in memory:
    • Big Endian:
      Hex: 0x00000401
      binary: 00000000 00000000 00000100 00000001
    • Little Endian:
      Hex: 0x01040000
      binary: 00000001 00000100 00000000 00000000

Decimal: 133124

  • 32 bit representation in memory:
    • Big Endian:
      Hex: 0x00020804
      binary:

      00000000 00000010 00001000 00000100
      bits 31-25 bits 24-16 bits 15-8 bits 7-0
    • Little Endian:
      Hex: 0x04080200
      binary:

      00000100 00001000 00000010 00000000
      bits 7-0 bits 15-8 bits 24-16 bits 31-25

Decimal: 1,099,511,892,096

  • 64 bit representation in memory:
    • Big Endian:
      Hex: 0x0000010000040880
      binary: 00000000 00000000 00000001 00000100 00000000 00000100 00001000 10000100
    • Little Endian:
      Hex: 0x8008040000010000
      binary: 10000100 00001000 00000100 00000000 00000100 00000001 00000000 00000000

There are currently two commonly used byte orders, big-endian and little-endian.
Big-endian: ABCD
little- endian : DCBA
little-endian Byte swap: CDAB
big-endian Byte swap: BADC

The four byte order expressions are listed below. Under the corresponding platform, the memory layout is four bytes of {0x00,0x01,0x02,0x03}, which is expressed as a hexadecimal value as shown in the following code.

ENDIAN_BIG      = 0x00010203,   			/* 大端序 ABCD */
ENDIAN_LITTLE       = 0x03020100,   		/* 小端序 DCBA */
ENDIAN_BIG_BYTESWAP     = 0x02030001,  		/* 中端序 CDAB, Honeywell 316 风格 */
ENDIAN_LITTLE_BYTESWAP  = 0x01000302    	/* 中端序 BADC, PDP-11 风格 */

Third, the core function code

#pragma once
//#include <type.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;
		}
	}
	
	// 将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;
	}
};

4. Software-related introduction:

MFC byte transcoding tool
For the specific implementation code, see the Github repository-ByteTranscodingTool.
This program is written in Visual Studio 2013 and uses a dialog-based interface. The features are as follows:
1. Support int16, int32, int64, uint16, uint32, uint64, float, double to 16 Hexadecimal bytecode
2. Support hexadecimal bytecode conversion to corresponding int16, int32, int64, uint16, uint32, uint64, float, double, support four combinations of big endian and Byte Swap:
(1) Big Endian
(2) Little
Endian (3) Big Endian, Byte Swap
(4) Little Endian , Byte Swap

References

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

Guess you like

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