C#结构体和字节数组的转换
来源:互联网 发布:淘宝的秒杀在哪里 编辑:程序博客网 时间:2024/05/09 20:21
http://www.haogongju.net/art/624248
在写C#TCP通信程序时,发送数据时,只能发送byte数组,处理起来比较麻烦不说,如果是和VC6.0等写的程序通信的话,很多的都是传送结构体,在VC6.0中可以很方便的把一个char[]数组转换为一个结构体,而在C#却不能直接把byte数组转换为结构体,要在C#中发送结构体,可以按以下方法实现:
(1)定义结构体:
//命名空间
using System.Runtime.InteropServices;
//注意这个属性不能少
[StructLayoutAttribute(LayoutKind.Sequential,CharSet=CharSet.Ansi,Pack=1)]
struct TestStruct
{
public int c;
//字符串,SizeConst为字符串的最大长度
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string str;
//int数组,SizeConst表示数组的个数,在转换成
//byte数组前必须先初始化数组,再使用,初始化
//的数组长度必须和SizeConst一致,例test = new int[6];
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public int[] test;
}
(2)结构体转byte数组:
//// <summary>
/// 结构体转byte数组
/// </summary>
/// <param name="structObj">要转换的结构体</param>
/// <returns>转换后的byte数组</returns>
public static byte[] StructToBytes(object structObj)
{
//得到结构体的大小
int size = Marshal.SizeOf(structObj);
//创建byte数组
byte[] bytes = new byte[size];
//分配结构体大小的内存空间
IntPtr structPtr = Marshal.AllocHGlobal(size);
//将结构体拷到分配好的内存空间
Marshal.StructureToPtr(structObj, structPtr, false);
//从内存空间拷到byte数组
Marshal.Copy(structPtr, bytes, 0, size);
//释放内存空间
Marshal.FreeHGlobal(structPtr);
//返回byte数组
return bytes;
}
(3)byte数组转结构体:
/// <summary>
/// byte数组转结构体
/// </summary>
/// <param name="bytes">byte数组</param>
/// <param name="type">结构体类型</param>
/// <returns>转换后的结构体</returns>
public static object BytesToStuct(byte[] bytes,Type type)
{
//得到结构体的大小
int size = Marshal.SizeOf(type);
//byte数组长度小于结构体的大小
if (size > bytes.Length)
{
//返回空
return null;
}
//分配结构体大小的内存空间
IntPtr structPtr = Marshal.AllocHGlobal(size);
//将byte数组拷到分配好的内存空间
Marshal.Copy(bytes,0,structPtr,size);
//将内存空间转换为目标结构体
object obj = Marshal.PtrToStructure(structPtr, type);
//释放内存空间
Marshal.FreeHGlobal(structPtr);
//返回结构体
return obj;
}
尽管在C#中结构与类有着惊人的相似度,但在实际应用中,会常常因为一些特殊之类而错误的使用它,下面几点内容是笔者认为应该注意的:
对于结构
1)可以有方法与属性
2)是密封的,不能被继承,或继承其他结构
3)结构隐式地继承自System.ValueType
4)结构有默认的无参数构造函数,可以将每个字段初始化为默认值,但这个默认的构造函数不能被替换,即使重载了带参数的构造函数
5)结构没有析构函数
6)除了const成员外,结构的字段不能在声明结构时初始化
7)结构是值类型,在定义时(尽管也使用new运算符)会分配堆栈空间,其值也存储于堆栈
8)结构主要用于小的数据结构,为了更好的性能,不要使用过于庞大的结构
9)可以像类那样为结构提供 Close() 或 Dispose() 方法
如果经常做通信方面的程序,结构体是非常有用的(为了更有效地组织数据,建议使用结构体),也会遇到字节数据与结构体相互转化的问题,下面是一般解决方法:
如何定义一个按字节顺序存储的结构体?
1 [StructLayout(LayoutKind.Sequential, Pack = 1)] //顺序排列,并按1字节对齐 (这里保存的是一组飞机参数,共73字节) 2public struct StructPlane 3 {
4public byte serialNum; 5public double pitch; 6public double roll; 7public double yaw; 8public double pitchVel; 9public double rollVel;10public double yawVel;11public double alt;12public double vz;13public ushort pwm1;14public ushort pwm2;15public ushort pwm3;16public ushort pwm4;17 };
结构体转字节数组的方法:
注:
1. 一般PC用小端模式(即高位存放于高地址,低位存放于低地址,反之为大端模式)存放数据,如果另一通讯设备用大端存储数据,则相互转化时就要注意了。
2. 结构体需按上面的方式,顺序排列并按1字节对齐,下面的所有方法都一样。
1 //需添加的引用,提供Marshal类2 using System.Runtime.InteropServices; 3 4/// <summary> 5/// 结构体转字节数组(按小端模式)6/// </summary> 7/// <param name="obj">struct type</param> 8/// <returns></returns> 9byte[] StructureToByteArray(object obj) 10 { 11int len = Marshal.SizeOf(obj); 12byte[] arr = new byte[len]; 13 IntPtr ptr = Marshal.AllocHGlobal(len); 14 Marshal.StructureToPtr(obj, ptr, true); 15 Marshal.Copy(ptr, arr, 0, len); 16 Marshal.FreeHGlobal(ptr); 17return arr; 18 } 19 20 /// <summary> 21/// 结构体转字节数组(按大端模式) 22/// </summary> 23/// <param name="obj">struct type</param> 24/// <returns></returns> 25byte[] StructureToByteArrayEndian(object obj) 26 { 27object thisBoxed = obj; //copy ,将 struct 装箱 28 Type test = thisBoxed.GetType(); 29 30int offset = 0; 31byte[] data = new byte[Marshal.SizeOf(thisBoxed)]; 32 33object fieldValue; 34 TypeCode typeCode; 35byte[] temp; 36// 列举结构体的每个成员,并Reverse 37foreach (var field in test.GetFields()) 38 { 39 fieldValue = field.GetValue(thisBoxed); // Get value 40 41 typeCode = Type.GetTypeCode(fieldValue.GetType()); // get type 42 43switch (typeCode) 44 { 45case TypeCode.Single: // float 46 { 47 temp = BitConverter.GetBytes((Single)fieldValue); 48 Array.Reverse(temp); 49 Array.Copy(temp, 0, data, offset, sizeof(Single)); 50break; 51 } 52case TypeCode.Int32: 53 { 54 temp = BitConverter.GetBytes((Int32)fieldValue); 55 Array.Reverse(temp); 56 Array.Copy(temp, 0, data, offset, sizeof(Int32)); 57break; 58 } 59case TypeCode.UInt32: 60 { 61 temp = BitConverter.GetBytes((UInt32)fieldValue); 62 Array.Reverse(temp); 63 Array.Copy(temp, 0, data, offset, sizeof(UInt32)); 64break; 65 } 66case TypeCode.Int16: 67 { 68 temp = BitConverter.GetBytes((Int16)fieldValue); 69 Array.Reverse(temp); 70 Array.Copy(temp, 0, data, offset, sizeof(Int16)); 71break; 72 } 73case TypeCode.UInt16: 74 { 75 temp = BitConverter.GetBytes((UInt16)fieldValue); 76 Array.Reverse(temp); 77 Array.Copy(temp, 0, data, offset, sizeof(UInt16)); 78break; 79 } 80case TypeCode.Int64: 81 { 82 temp = BitConverter.GetBytes((Int64)fieldValue); 83 Array.Reverse(temp); 84 Array.Copy(temp, 0, data, offset, sizeof(Int64)); 85break; 86 } 87case TypeCode.UInt64: 88 { 89 temp = BitConverter.GetBytes((UInt64)fieldValue); 90 Array.Reverse(temp); 91 Array.Copy(temp, 0, data, offset, sizeof(UInt64)); 92break; 93 } 94case TypeCode.Double: 95 { 96 temp = BitConverter.GetBytes((Double)fieldValue); 97 Array.Reverse(temp); 98 Array.Copy(temp, 0, data, offset, sizeof(Double)); 99break;100 }101case TypeCode.Byte:102 {103 data[offset] = (Byte)fieldValue;104break;105 }106default:107 {108//System.Diagnostics.Debug.Fail("No conversion provided for this type : " + typeCode.ToString());109break;110 }111 }; // switch112if (typeCode == TypeCode.Object)113 {114int length = ((byte[])fieldValue).Length;115 Array.Copy(((byte[])fieldValue), 0, data, offset, length);116 offset += length;117 }118else119 {120 offset += Marshal.SizeOf(fieldValue);121 }122 } // foreach123 124return data;125 } // Swap
字节数组转结构体的方法:
/// <summary>/// 字节数组转结构体(按小端模式)/// </summary>/// <param name="bytearray">字节数组</param>/// <param name="obj">目标结构体</param>/// <param name="startoffset">bytearray内的起始位置</param>public static void ByteArrayToStructure(byte[] bytearray, ref object obj, int startoffset) {int len = Marshal.SizeOf(obj); IntPtr i = Marshal.AllocHGlobal(len);// 从结构体指针构造结构体obj = Marshal.PtrToStructure(i, obj.GetType());try {// 将字节数组复制到结构体指针Marshal.Copy(bytearray, startoffset, i, len); }catch (Exception ex) { Console.WriteLine("ByteArrayToStructure FAIL: error " + ex.ToString()); } obj = Marshal.PtrToStructure(i, obj.GetType()); Marshal.FreeHGlobal(i); //释放内存,与 AllocHGlobal() 对应}/// <summary>/// 字节数组转结构体(按大端模式)/// </summary>/// <param name="bytearray">字节数组</param>/// <param name="obj">目标结构体</param>/// <param name="startoffset">bytearray内的起始位置</param>public static void ByteArrayToStructureEndian(byte[] bytearray, ref object obj, int startoffset) {int len = Marshal.SizeOf(obj); IntPtr i = Marshal.AllocHGlobal(len);byte[] temparray = (byte[])bytearray.Clone();// 从结构体指针构造结构体obj = Marshal.PtrToStructure(i, obj.GetType());// 做大端转换object thisBoxed = obj; Type test = thisBoxed.GetType();int reversestartoffset = startoffset;// 列举结构体的每个成员,并Reverseforeach (var field in test.GetFields()) {object fieldValue = field.GetValue(thisBoxed); // Get value TypeCode typeCode = Type.GetTypeCode(fieldValue.GetType()); //Get Typeif (typeCode != TypeCode.Object) //如果为值类型{Array.Reverse(temparray, reversestartoffset, Marshal.SizeOf(fieldValue)); reversestartoffset += Marshal.SizeOf(fieldValue); }else//如果为引用类型{reversestartoffset += ((byte[])fieldValue).Length; } }try {//将字节数组复制到结构体指针Marshal.Copy(temparray, startoffset, i, len); }catch (Exception ex) { Console.WriteLine("ByteArrayToStructure FAIL: error " + ex.ToString()); } obj = Marshal.PtrToStructure(i, obj.GetType()); Marshal.FreeHGlobal(i); //释放内存}
使用示例一:
... ...byte[] packet = new byte[73]{...};StructPlane structPlane = new StructPlane(); object structType = structPlane;ByteArrayToStructure(packet, ref structType, 0);
使用示例二:
StructPlane structPlane = new StructPlane();structPlane.serialNum = ...;structPlane.time = ...;structPlane.pitch = ...;... ...byte[] datas = StructureToByteArray(structPlane);
http://www.haogongju.net/art/1200066
- C#结构体和字节数组的转换
- C#结构体和字节数组的转换
- C#结构体和字节数组的转换
- C#结构体和字节数组的转换
- C#结构体和字节数组的转换
- C# 结构体和字节数组的转换
- C#结构体和字节数组的转换
- C#结构体和字节数组的转换
- C#结构体和字节数组的转换
- C#结构体和字节数组的转换函数
- C# 结构体和字节数组的转换
- 字节数组与结构体的转换
- C# 转换uint,byte[],char[],string, short[]<->byte[] 结构体和字节数组转化
- C# 字节数组 到 结构体的强制转换 及解引用相关问题
- C#网络编程中结构体与字节数组的转换
- labview和c#的string到字节数组的转换
- C# 字节数组和字符串的相互转换
- C#之基础数据类型和字节数组的转换
- Problems with Multiple QApplications(同时运行两个qt embedded程序)
- 获取Spinner的选中项的值
- 从虚拟地址转为物理地址
- 黑马程序员---类的属性和构造方法
- 抄一个汉字转汉语拼音缩写的存储过程
- C#结构体和字节数组的转换
- 官方NotePad实例学习--上下文菜单ContextMenu的使用
- bootloader启动图示
- 中断例子
- IT人保持健康的必备法宝
- struts2配置结果页面路径以节省配置--shopxx学习
- JSP获取header信息request列表
- 关于观察者模式的问题
- SQL Server数据库性能优化之SQL语句篇