前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >字节数组和short,int,float,double等类型的相互转换

字节数组和short,int,float,double等类型的相互转换

作者头像
ccf19881030
发布2020-03-18 20:34:39
5.3K0
发布2020-03-18 20:34:39
举报
文章被收录于专栏:ccf19881030的博客ccf19881030的博客

一、在C++中从字节数组中获取short,int,long,float,double等数据

在进行Modbus协议通信和网络编程时,有时需要将从串口或者网络中接收的数据从字节数组转换成对应的int,float,double等数据,有时还要考虑大小端字节序以及Swap的问题,发现在C++中需要自己写相关的转换函数,于是/写了一个函数,用于从输入的byte数组中获取指定类型的数据,目前支持int16,int32,int64,float,double,对应的代码如下:

代码语言:javascript
复制
#ifndef _BYTECONVERTTOOLS_H
#define _BYTECONVERTTOOLS_H

#include <algorithm>
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) {
				// 小端字节序
				std::copy(buffer + startPos, buffer + endPos, std::back_inserter(tmp8));
			}
			else {
				// 大端字节序,则将字节数组进行反转
				std::reverse_copy(buffer + startPos, buffer + endPos, std::back_inserter(tmp8));
			}
			// 将8位的数组tmp8转换成16位的数组tmp16
			memcpy(tmp16.data(), tmp8.data(), byteNum);
			if (isSwapByte)
			{
				// 将tmp16反转
				std::reverse(tmp16.begin(), tmp16.end());
				Uint8Array tmp1(byteNum);
				// 将16位的tmp16转换成8位的tmp1
				memcpy(tmp1.data(), tmp16.data(), byteNum);
				// 将tmp1进行反转
				std::reverse(tmp1.begin(), tmp1.end());
				// 将tmp1的内容拷贝到tmp16中
				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);
	}
};

#endif

main.cpp测试代码

代码语言:javascript
复制
#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;
}

二、C#中字节数组和基本数据类型的相互转换

在C#中对字节数组和short,int,float,double等的相互转换,提供了一个非常方便的类BitConverter 正如微软官方文档描述的那样:BitConverter Class:Converts base data types to an array of bytes, and an array of bytes to base data types. 也就是说BitConverter类对字节数组和基本的数据类型进行相互转换。 首先,BitCoverter类有一个IsLittleEndian属性,用于判断计算机的体系结构是大端字节序还是小端字节序,大小端这个概念在嵌入式编程和网路编程、串口编程中很常见。另外,C#中直接提供了byte数据类型,类似于C和C++中的unsigned char

数据类型

方法

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)

官方提供了一下简单的示例程序,代码如下:

代码语言:javascript
复制
// 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
*/

经过测试,我的Thinkpad电脑是小端字节序 关于在C#中将字节数组转换成int,可以参考How to convert a byte array to an int (C# Programming Guide),对应的测试代码如下:

1. Example1

本示例初始化一个字节数组,如果计算机体系结构是小端字节序(即,首先存储最低有效字节),则反转该数组,然后调用ToInt32(Byte [],Int32)方法来转换四个字节。 将该数组转换为一个int。 ToInt32(Byte [],Int32)的第二个参数指定字节数组的起始索引。 注意:输出结果会根据你的计算机的体系而不同。

代码语言:javascript
复制
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

本则示例,使用BitConvert类的GetBytes(int32)方法将int转换成字节数组 注意:结果会根据你的计算机的体系的大小端而不同。 代码如下:

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

完整的C#代码如下:

代码语言:javascript
复制
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
        }
    }
}

参考资料

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-03-16 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、在C++中从字节数组中获取short,int,long,float,double等数据
  • 二、C#中字节数组和基本数据类型的相互转换
    • 1. Example1
      • 2.Example2
      • 参考资料
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档