C#借助FieldOffset属性实现共用体与强制类型转换

转: C#借助FieldOffset属性实现共用体与强制类型转换


C#上还是新手,突然就接触到属性是不是有点超前了呢。先Mark下来。如果对于文章中的问题有更好的解决办法请告诉我。

C#借助FieldOffset属性实现共用体与强制类型转换

    这两天被C#的强制类型转换弄得有点不习惯。事出如此。

    在C#中,我打算读二进制文。文件的结构很简单,一连串的紧密存储的int32值,以二进制方式存放。现在我希望随机读取第n个int32开始的i个值,并读入到数组中。结果查一下C#只能读到byte[]中,要不就是一个个读出来循环放int[]。追求效率的我当然不希望这样,如果能像C++那样将byte[]强制转换成int[]就好了。例如:

[cpp]  view plain  copy
 print ?
  1. char tmp[64];       // 16个int。相当于C#的 byte[] tmp = new int[64];  
  2. int* dat;       // dat的指针。相当于C#的 int[] dat;  
  3. ifstream IF(...);   // 标准文件输入流。相当于C#的 FileStream FS = new FileStream(...);  
  4. IF.read(tmp, 64);   // 读取64个字节。  相当于C#的 FS.Read(tmp,0,64);  
  5. dat = (int*)tmp;    // 将tmp数组的首地址转为int类型,则数组以4个字节为一个int转换为int型的数组。  
  6.             // 数据在内存上没有任何变化,因为数据本来就是int型的。  
  7.                         // 关键是这一步在C#中无法直接实现。  
  8. for (int i = 0; i < 16; i++)  
  9.     cout << dat[i] << " "// 输出数据。相当于C#的 Console.Write(dat[i]+" ");  

在C#中无法直接实现,为此我想了好些办法,也查了好久,直到我见到了这样的代码:

[csharp]  view plain  copy
 print ?
  1. using System;  
  2. using System.IO;  
  3. using System.Collections.Generic;  
  4. using System.Linq;  
  5. using System.Text;  
  6. // 提供各种各样支持 COM 互操作 及平台调用服务的成员  
  7. using System.Runtime.InteropServices;  
  8.   
  9. namespace test  
  10. {  
  11.     class Program  
  12.     {  
  13.         // StructLayout使设计者可以控制类或结构的数据字段的物理布局  
  14.         // Explicit与FieldOffset一起可以控制每个数据成员的精确位置  
  15.         [StructLayout(LayoutKind.Explicit)]  
  16.         public struct S1  
  17.         {  
  18.             // FieldOffset控制字段所在的物理位置偏移为0  
  19.             [FieldOffset(0)]  
  20.             public byte[] a;  
  21.             // 同样偏移为0,开始位置与a重叠了。  
  22.             [FieldOffset(0)]  
  23.             public int[] b;  
  24.         }  
  25.   
  26.         static void Main(string[] args)  
  27.         {  
  28.             S1 s = new S1(); // 要new,不然b会报“使用了可能未赋值的字段”  
  29.             s.a=new byte[64];  
  30.   
  31.             FileStream FS = new FileStream("E:\\test.txt", FileMode.Open);  
  32.             // 以s.a来接收文件的数据  
  33.             FS.Read(s.a,0,64);  
  34.   
  35.             // 自己保证读b的时候不要越界  
  36.             for (int i = 0; i < 16; i++)   
  37.                 Console.Write(s.b[i]+" "); // 以b来使用数据  
  38.   
  39.             Console.ReadKey();  
  40.         }  
  41.     }  
  42. }  

原理实际上跟C++一样,将一个int[]型的变量指向与byte[]型变量相同的内存区域,跟C++中将dat指向char数组的首地址是一样的。同样,这样的结构体功能与C++的共用体是一样的,即一个结构可以作为多种数据类型,而具体是什么类型视情况而定。

测试所使用的文件就不上传了,有WinHex的可以自己编辑一个,没有的也可以写程序将从0xF到0x0的16个数以二进制方式输出到文件中。文件的内容用WinHex打开以16进制显示应该如下:

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值