一.基础篇 C#不像C++,他本身是没有联合Union的,但是可以通过手动控制结构体每个元素的位置来实现,这需要结合使用 StructLayoutAttribute、LayoutKind以及FieldOffsetAttribute 。使用它们的时候必须引用System.Runtime.InteropServices下面是我写的模拟U的
一.基础篇
C#不像C++,他本身是没有联合Union的,但是可以通过手动控制结构体每个元素的位置来实现,这需要结合使用StructLayoutAttribute、LayoutKind以及FieldOffsetAttribute。使用它们的时候必须引用System.Runtime.InteropServices下面是我写的模拟U的联合。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | [StructLayout(LayoutKind.Explicit, Size = <span style= "color: #800080;" >4</span><span style= "color: #000000;" >)]
</span><span style= "color: #0000ff;" >struct</span><span style= "color: #000000;" > U
{
[FieldOffset(</span><span style= "color: #800080;" >0</span><span style= "color: #000000;" >)]
</span><span style= "color: #0000ff;" > public </span> <span style= "color: #0000ff;" >byte</span><span style= "color: #000000;" > b0;
[FieldOffset(</span><span style= "color: #800080;" >1</span><span style= "color: #000000;" >)]
</span><span style= "color: #0000ff;" > public </span> <span style= "color: #0000ff;" >byte</span><span style= "color: #000000;" > b1;
[FieldOffset(</span><span style= "color: #800080;" >2</span><span style= "color: #000000;" >)]
</span><span style= "color: #0000ff;" > public </span> <span style= "color: #0000ff;" >byte</span><span style= "color: #000000;" > b2;
[FieldOffset(</span><span style= "color: #800080;" >3</span><span style= "color: #000000;" >)]
</span><span style= "color: #0000ff;" > public </span> <span style= "color: #0000ff;" >byte</span><span style= "color: #000000;" > b3;
[FieldOffset(</span><span style= "color: #800080;" >0</span><span style= "color: #000000;" >)]
</span><span style= "color: #0000ff;" > public </span> <span style= "color: #0000ff;" >int</span><span style= "color: #000000;" > i;
[FieldOffset(</span><span style= "color: #800080;" >0</span><span style= "color: #000000;" >)]
</span><span style= "color: #0000ff;" > public </span> <span style= "color: #0000ff;" >float</span><span style= "color: #000000;" > f;
}</span>
|
로그인 후 복사
我们知道联合中每个数据成员都在相同的内存地址开始,所以我们要通过[FieldOffset(0)]应用到U的每一个成员,意思就是让这些成员处于同一个开始位置。当然,我们得事先告诉.NET这些成员的内存布局由我们来作主,所以要使用LayoutKind.Explicit枚举然后传递给StructLayoutAttribute,并应用到U上,这样.Net就不会再干涉该struct的成员在内存中的布局了。并且我定义了U的Size为12,当然你也可以不定义U的Size。
而且使用联合进行数据转换比BitConverter要快。测试用例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <span style= "color: #000000;" >{
DateTime past </span>=<span style= "color: #000000;" > DateTime.Now;
</span><span style= "color: #0000ff;" >int</span> length = <span style= "color: #800080;" >500000</span> * <span style= "color: #800080;" >3</span> * <span style= "color: #800080;" >3</span><span style= "color: #000000;" >;
</span><span style= "color: #0000ff;" > for </span> (<span style= "color: #0000ff;" >int</span> i = <span style= "color: #800080;" >0</span>; i < length; i++<span style= "color: #000000;" >)
{
U a </span>= <span style= "color: #0000ff;" > new </span><span style= "color: #000000;" > U();
a.b0 </span>= <span style= "color: #800080;" >0xFF</span><span style= "color: #000000;" >;
a.b1 </span>= <span style= "color: #800080;" >0xFF</span><span style= "color: #000000;" >;
</span><span style= "color: #0000ff;" >int</span> res =<span style= "color: #000000;" > a.i;
}
DateTime now </span>=<span style= "color: #000000;" > DateTime.Now;
Console.WriteLine((now </span>-<span style= "color: #000000;" > past));
}
{
DateTime past </span>=<span style= "color: #000000;" > DateTime.Now;
</span><span style= "color: #0000ff;" >int</span> length = <span style= "color: #800080;" >500000</span> * <span style= "color: #800080;" >3</span> * <span style= "color: #800080;" >3</span><span style= "color: #000000;" >;
</span><span style= "color: #0000ff;" > for </span> (<span style= "color: #0000ff;" >int</span> i = <span style= "color: #800080;" >0</span>; i < length; i++<span style= "color: #000000;" >)
{
</span><span style= "color: #0000ff;" >byte</span>[] a = { <span style= "color: #800080;" >0xFF</span>, <span style= "color: #800080;" >0x0F</span>, <span style= "color: #800080;" >0x0F</span>, <span style= "color: #800080;" >0</span><span style= "color: #000000;" > };
</span><span style= "color: #0000ff;" >object</span> b =<span style= "color: #000000;" > a;
</span><span style= "color: #0000ff;" >int</span> res = BitConverter.ToInt32(a, <span style= "color: #800080;" >0</span><span style= "color: #000000;" >);
}
DateTime now </span>=<span style= "color: #000000;" > DateTime.Now;
Console.WriteLine((now </span>-<span style= "color: #000000;" > past));
}</span>
|
로그인 후 복사
二.进阶篇
之前的方法还存在好多问题,比如数组没法放入联合中,会提示值和引用冲突什么的。
今天又研究了一下,利用C#中可以使用指针的特性,结合unsafe和fixed,实现数组类型和普通值类型的共存。
方法① 数组类型和普通值类型的共存——固定大小的缓冲区
利用固定大小的缓冲区(fixed)实现数组类型和普通值类型的共存
1 2 3 4 5 6 7 8 9 10 11 12 | [StructLayoutAttribute(LayoutKind.Explicit, Pack = <span style= "color: #800080;" >1</span><span style= "color: #000000;" >)]
</span><span style= "color: #0000ff;" > public </span> <span style= "color: #0000ff;" >unsafe</span> <span style= "color: #0000ff;" >struct</span><span style= "color: #000000;" > A
{
[FieldOffset(</span><span style= "color: #800080;" >0</span><span style= "color: #000000;" >)]
</span><span style= "color: #0000ff;" > public </span> <span style= "color: #0000ff;" >int</span><span style= "color: #000000;" > a;
[FieldOffset(</span><span style= "color: #800080;" >0</span><span style= "color: #000000;" >)]
</span><span style= "color: #0000ff;" > public </span> <span style= "color: #0000ff;" >byte</span><span style= "color: #000000;" > b;
[FieldOffset(</span><span style= "color: #800080;" >0</span><span style= "color: #000000;" >)]
</span><span style= "color: #0000ff;" > public </span> <span style= "color: #0000ff;" >float</span><span style= "color: #000000;" > c;
[FieldOffset(</span><span style= "color: #800080;" >0</span><span style= "color: #000000;" >)]
</span><span style= "color: #0000ff;" > public </span> <span style= "color: #0000ff;" >fixed</span> <span style= "color: #0000ff;" >byte</span> arr[<span style= "color: #800080;" >9</span><span style= "color: #000000;" >];
};</span>
|
로그인 후 복사
方法② 结构体转字节数组——1).使用联合 2).使用指针强制转换
1).使用联合,利用一个和原结构体等长的fixed byte buff[n],这个buff就是我们要的直接数组,访问时需要通过fixed (byte* ta = a.buff) {}来访问。
1 2 3 4 5 6 7 8 9 10 11 12 | [StructLayoutAttribute(LayoutKind.Explicit, Pack = <span style= "color: #800080;" >1</span><span style= "color: #000000;" >)]
</span><span style= "color: #0000ff;" > public </span> <span style= "color: #0000ff;" >unsafe</span> <span style= "color: #0000ff;" >struct</span><span style= "color: #000000;" > A
{
[FieldOffset(</span><span style= "color: #800080;" >0</span><span style= "color: #000000;" >)]
</span><span style= "color: #0000ff;" > public </span> <span style= "color: #0000ff;" >int</span><span style= "color: #000000;" > a;
[FieldOffset(</span><span style= "color: #800080;" >4</span><span style= "color: #000000;" >)]
</span><span style= "color: #0000ff;" > public </span> <span style= "color: #0000ff;" >byte</span><span style= "color: #000000;" > b;
[FieldOffset(</span><span style= "color: #800080;" >5</span><span style= "color: #000000;" >)]
</span><span style= "color: #0000ff;" > public </span> <span style= "color: #0000ff;" >float</span><span style= "color: #000000;" > c;
[FieldOffset(</span><span style= "color: #800080;" >0</span><span style= "color: #000000;" >)]
</span><span style= "color: #0000ff;" > public </span> <span style= "color: #0000ff;" >fixed</span> <span style= "color: #0000ff;" >byte</span> buff[<span style= "color: #800080;" >9</span><span style= "color: #000000;" >];
};</span>
|
로그인 후 복사
2).直接使用指针强制转换,通过fixed,先将结构体转换为void *,再将其转化为byte* b。
1 2 3 4 | <span style= "color: #0000ff;" >fixed</span> (<span style= "color: #0000ff;" >void</span> * ta = &<span style= "color: #000000;" >a)
{
</span><span style= "color: #0000ff;" >byte</span>* b = (<span style= "color: #0000ff;" >byte</span>*<span style= "color: #000000;" >)ta ;
}</span>
|
로그인 후 복사
3).最后通过IntPtr拷贝到C#标准的byte[]中。
1 2 3 | <span style= "color: #0000ff;" >byte</span>[] Dbuff = <span style= "color: #0000ff;" > new </span> <span style= "color: #0000ff;" >byte</span>[<span style= "color: #800080;" >9</span><span style= "color: #000000;" >];
IntPtr pstart </span>= <span style= "color: #0000ff;" > new </span><span style= "color: #000000;" > IntPtr(a);
Marshal. Copy (pstart, Dbuff, </span><span style= "color: #800080;" >0</span>, <span style= "color: #800080;" >9</span>);
|
로그인 후 복사