field Offset属性
单片机发送浮点数数采用联合体数据转化好像挺高效的(目前的使用中并没有太深入了解高效、内存等问题),C#中没有联合体的数据类型,可以通过使用特性可以自定义结构在内存中的布局方式,即通过一定的方式直接指定位置偏移量,以创建在 C/C++ 中称为联合的布局。 此时需引用程序集 :using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Explicit)]
public struct union //union只是自己起的名字
{
[FieldOffset(0)] /作为数据头使用
public byte temple0;
[FieldOffset(1)]
public byte temple1;
[FieldOffset(2)]
public byte temple2;
[FieldOffset(3)]
public byte temple3;
[FieldOffset(4)]
public byte temple4;
[FieldOffset(5)]
public byte temple5;
[FieldOffset(6)]
public byte temple6;
[FieldOffset(7)]
public byte temple7;
[FieldOffset(8)]
public byte temple8;
[FieldOffset(9)] //作为数据尾使用
public byte temple9;
[FieldOffset(1)] //偏移量回归
public float dataGPSLng;
[FieldOffset(5)]
public float dataGPSLat;
}
- [StructLayout(LayoutKind.Explicit)]
LayoutKind
是一个枚举类型,有 Auto、 Explicit、 Sequential三种,它和 StructLayoutAttribute 一起使用; 默认情况下,公共语言运行库(common language runtime)使用的是Auto, 而C#, Visual Basic, and C++ compilers 为减少Auto的错误,对于结构 默认使用Sequential,而对于类,顺序布局则必须显示指明LayoutKind.Sequential;
Explicit
: 精确布局
** 需要用FieldOffset() 设置 每个成员 的位置, 这样就可以实现类似c的公用体的功能;
Sequential
: 顺序布局
** 即先排完前一个在紧接着拍下一个,两个地址差为前者的字节长;因为C#默认使用这个,使用加不加效果一样的;
StructLayout
/* [StructLayout(LayoutKind.Explicit, Size=16, CharSet=CharSet.Ansi)] */
StructLayout
: 结构布局属性, 允许自己控制内存中类或结构的数据字段的物理布局;支持三种可选字段:CharSet、 Pack、Size;
CharSet :目前没用到,不写了,,
Size
:指示类或结构的绝对大小;
Pack
:控制内存中类或结构的数据字段的对齐方式;它同时影响顺序和精确布局,其值必须为0、1、2、4、8、16、32、64或 128;默认情况下值为0,指示当前平台的默认包装大小;因为自己写的时候是规定了每一个字节,所以内存对齐了,要是不对齐要看看官网:
https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.structlayoutattribute.pack?view=netframework-4.7.2
Tips:
** 在使用这个时本来想用数组和float的,但是报错说值类型与引用类型在这里不能同时引用,(类(数组为类)为引用类型,而结构为值类型), 后来搜是有办法让数组类型和普通值类型的共存的办法(没有测试过)
https://www.cnblogs.com/chihirosan/archive/2016/01/28/5166057.html
..............调用...........
private delegate void ReceiveGPSDataDelagate(float longitude, float latitude);
private ReceiveGPSDataDelagate receiveGPSDataDelagate;
................
union reData = new union();
byte[] ReDatasTemp = new byte[10]; //用于先存储一次发过来的数据, byte即是无符号整型
Port.Read(ReDatasTemp, 0, ReDatasTemp.Length);
if ((ReDatasTemp[0] == 0x65) && (ReDatasTemp[9] == 0x66))
{
reData.temple1 = ReDatasTemp[1];
reData.temple2 = ReDatasTemp[2];
reData.temple3 = ReDatasTemp[3];
reData.temple4 = ReDatasTemp[4];
reData.temple5 = ReDatasTemp[5];
reData.temple6 = ReDatasTemp[6];
reData.temple7 = ReDatasTemp[7];
reData.temple8 = ReDatasTemp[8];
receiveGPSDataDelagate = new ReceiveGPSDataDelagate(ChangeGPSText); //实例化委托类型变量
Dispatcher.Invoke(receiveGPSDataDelagate, reData.dataGpsLng, reData.dataGpsLat); //调用异步线程
}