您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

C#联合Union的实现方式

2024/5/6 22:47:00发布18次查看
一.基础篇 c#不像c++,他本身是没有联合union的,但是可以通过手动控制结构体每个元素的位置来实现,这需要结合使用 structlayoutattribute、layoutkind以及fieldoffsetattribute 。使用它们的时候必须引用system.runtime.interopservices下面是我写的模拟u的
一.基础篇
        c#不像c++,他本身是没有联合union的,但是可以通过手动控制结构体每个元素的位置来实现,这需要结合使用structlayoutattribute、layoutkind以及fieldoffsetattribute。使用它们的时候必须引用system.runtime.interopservices下面是我写的模拟u的联合。
[structlayout(layoutkind.explicit, size = 4)]struct u{ [fieldoffset(0)] public byte b0; [fieldoffset(1)] public byte b1; [fieldoffset(2)] public byte b2; [fieldoffset(3)] public byte b3; [fieldoffset(0)] public int i; [fieldoffset(0)] public float f;}
我们知道联合中每个数据成员都在相同的内存地址开始,所以我们要通过[fieldoffset(0)]应用到u的每一个成员,意思就是让这些成员处于同一个开始位置。当然,我们得事先告诉.net这些成员的内存布局由我们来作主,所以要使用layoutkind.explicit枚举然后传递给structlayoutattribute,并应用到u上,这样.net就不会再干涉该struct的成员在内存中的布局了。并且我定义了u的size为12,当然你也可以不定义u的size。
而且使用联合进行数据转换比bitconverter要快。测试用例如下:
{ datetime past = datetime.now; int length = 500000 * 3 * 3; for (int i = 0; i < length; i++) { u a = new u(); a.b0 = 0xff; a.b1 = 0xff; int res = a.i; } datetime now = datetime.now; console.writeline((now - past));} { datetime past = datetime.now; int length = 500000 * 3 * 3; for (int i = 0; i < length; i++) { byte[] a = { 0xff, 0x0f, 0x0f, 0 }; object b = a; int res = bitconverter.toint32(a, 0); } datetime now = datetime.now; console.writeline((now - past));}
二.进阶篇
之前的方法还存在好多问题,比如数组没法放入联合中,会提示值和引用冲突什么的。
今天又研究了一下,利用c#中可以使用指针的特性,结合unsafe和fixed,实现数组类型和普通值类型的共存。
方法①  数组类型和普通值类型的共存——固定大小的缓冲区
利用固定大小的缓冲区(fixed)实现数组类型和普通值类型的共存
[structlayoutattribute(layoutkind.explicit, pack = 1)]public unsafe struct a{ [fieldoffset(0)] public int a; [fieldoffset(0)] public byte b; [fieldoffset(0)] public float c; [fieldoffset(0)] public fixed byte arr[9];};
方法②  结构体转字节数组——1).使用联合 2).使用指针强制转换
1).使用联合,利用一个和原结构体等长的fixed byte buff[n],这个buff就是我们要的直接数组,访问时需要通过fixed (byte* ta = a.buff) {}来访问。
[structlayoutattribute(layoutkind.explicit, pack = 1)]public unsafe struct a{ [fieldoffset(0)] public int a; [fieldoffset(4)] public byte b; [fieldoffset(5)] public float c; [fieldoffset(0)] public fixed byte buff[9];};
2).直接使用指针强制转换,通过fixed,先将结构体转换为void *,再将其转化为byte* b。
fixed (void * ta = &a){ byte* b = (byte*)ta ;}
3).最后通过intptr拷贝到c#标准的byte[]中。
byte[] dbuff = new byte[9];intptr pstart = new intptr(a);marshal.copy(pstart, dbuff, 0, 9);
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product