> php教程 > php手册 > C#联合Union的实现方式

C#联合Union的实现方式

WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWB
풀어 주다: 2016-07-06 13:30:20
원래의
1170명이 탐색했습니다.

一.基础篇 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>);

로그인 후 복사

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 추천
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿