分享

概述C#语言的结构体

 scholes_goal 2011-06-02
    这里介绍C#语言的结构体是一个比较复杂的东西,在此之上有很多需要设置的参数,否则用起来就很容易出错。下面是msdn上一段描述,看看也许有助于理解C#语言的结构体。

    最近一直在研究。Net Micro Framework字体文件(tinyfnt),由于tinyfnt文件头部有一段描述数据,所以很想定义一个结构体,像VC一样直接从文件中读出来,省得用流一个个解析很是麻烦。

    没有想到在C#中竟没有直接的指令,想必C#设计者认为提供了流和序列化技术,一切问题都可以迎刃而解了。

    C#语言的结构体是一个比较复杂的东西,在此之上有很多需要设置的参数,否则用起来就很容易出错。下面是msdn上一段描述,看看也许有助于理解C#语言的结构体。

    通过使用属性可以自定义结构在内存中的布局方式。例如,可以使用 StructLayout(LayoutKind.Explicit) 和 FieldOffset 属性创建在 C/C++ 中称为联合的布局。

    1. [System.Runtime.InteropServices.StructLayout(LayoutKind.Explicit)]  
    2. struct TestUnion  
    3. {  
    4. [System.Runtime.InteropServices.FieldOffset(0)]  
    5. public int i;  
    6. [System.Runtime.InteropServices.FieldOffset(0)]  
    7. public double d;  
    8. [System.Runtime.InteropServices.FieldOffset(0)]  
    9. public char c;  
    10. [System.Runtime.InteropServices.FieldOffset(0)]  
    11. public byte b;  

    在上一个代码段中,TestUnion 的所有字段都从内存中的同一位置开始。

    以下是字段从其他显式设置的位置开始的另一个示例。

    1. [System.Runtime.InteropServices.StructLayout(LayoutKind.Explicit)]  
    2. struct TestExplicit  
    3. {  
    4. [System.Runtime.InteropServices.FieldOffset(0)]  
    5. public long lg;  
    6. [System.Runtime.InteropServices.FieldOffset(0)]  
    7. public int i1;  
    8. [System.Runtime.InteropServices.FieldOffset(4)]  
    9. public int i2;  
    10. [System.Runtime.InteropServices.FieldOffset(8)]  
    11. public double d;  
    12. [System.Runtime.InteropServices.FieldOffset(12)]  
    13. public char c;  
    14. [System.Runtime.InteropServices.FieldOffset(14)]  
    15. public byte b;  

    i1 和 i2 这两个 int 字段共享与 lg 相同的内存位置。使用平台调用时,这种结构布局控制很有用。

    我做了一个简单的测试程序,基本达成预定需求,不过程序该方式要求比较苛刻,如果要解析的数据与转换C#语言的结构体不匹配就会引发一系列莫名其妙的异常(如内存不可读等等之类),下面是测试程序的源代码,有兴趣的朋友可以看一看,也希望网友能提出更好的方案。

    1. using System;  
    2. using System.Collections.Generic;  
    3. using System.ComponentModel;  
    4. using System.Data;  
    5. using System.Drawing;  
    6. using System.Text;  
    7. using System.Windows.Forms;  
    8. using System.IO;  
    9. using System.Runtime.InteropServices;  
    10.  
    11. namespace RWFile  
    12. {  
    13. public partial class Form1 : Form  
    14. {  
    15. public Form1()  
    16. {  
    17. InitializeComponent();  
    18. }  
    19. //从文件中读结构体  
    20. private void button1_Click(object sender, EventArgs e)  
    21. {  
    22. string strFile = Application.StartupPath + "\\test.dat";  
    23. if (!File.Exists(strFile))  
    24. {  
    25. MessageBox.Show("文件不存在");  
    26. return;  
    27. }  
    28.  
    29. FileStream fs = new FileStream(strFile, FileMode.Open,  
    30.  
    31. FileAccess.ReadWrite);  
    32. TestStruct ts = new TestStruct();  
    33. byte[] bytData = new byte[Marshal.SizeOf(ts)];  
    34. fs.Read(bytData, 0, bytData.Length);  
    35. fs.Close();  
    36. ts = rawDeserialize(bytData);  
    37. textBox1.Text = ts.dTest.ToString();  
    38. textBox2.Text = ts.uTest.ToString();  
    39. textBox3.Text = Encoding.Default.GetString(ts.bTest);  
    40. }  
    41.  
    42. //向文件中写结构体  
    43. private void button2_Click(object sender, EventArgs e)  
    44. {  
    45. string strFile = Application.StartupPath + "\\test.dat";  
    46. FileStream fs = new FileStream(strFile, FileMode.Create ,  
    47. FileAccess.Write);  
    48. TestStruct ts = new TestStruct();  
    49. ts.dTest = double.Parse(textBox1.Text);  
    50. ts.uTest = UInt16.Parse(textBox2.Text);  
    51. ts.bTest = Encoding.Default.GetBytes(textBox3.Text);  
    52. byte[] bytData = rawSerialize(ts);  
    53. fs.Write(bytData, 0, bytData.Length);  
    54. fs.Close();  
    55. }  
    56.  
    57. [StructLayout(LayoutKind.Sequential,CharSetCharSet = CharSet.Ansi)] //,Size=16 
    58. public struct TestStruct  
    59. {  
    60. [MarshalAs(UnmanagedType.R8)] //,FieldOffset(0)]   
    61. public double dTest;  
    62. [MarshalAs(UnmanagedType.U2)] //, FieldOffset(8)]  
    63. public UInt16 uTest;  
    64. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]  
    65. //, FieldOffset(10)]  
    66. public byte[] bTest;  
    67. }  
    68.  
    69. //序列化  
    70. public static byte[] rawSerialize(object obj)  
    71. {  
    72. int rawsize = Marshal.SizeOf(obj);  
    73. IntPtr buffer = Marshal.AllocHGlobal(rawsize);  
    74. Marshal.StructureToPtr(obj, buffer, false);  
    75. byte[] rawdatas = new byte[rawsize];  
    76. Marshal.Copy(buffer, rawdatas, 0, rawsize);  
    77. Marshal.FreeHGlobal(buffer);  
    78. return rawdatas;  
    79. }  
    80.  
    81. //反序列化  
    82. public static TestStruct rawDeserialize(byte[] rawdatas)  
    83. {  
    84. Type anytype = typeof(TestStruct);  
    85. int rawsize = Marshal.SizeOf(anytype);  
    86. if (rawsize > rawdatas.Length) return new TestStruct();  
    87. IntPtr buffer = Marshal.AllocHGlobal(rawsize);  
    88. Marshal.Copy(rawdatas, 0, buffer, rawsize);  
    89. object retobj = Marshal.PtrToStructure(buffer, anytype);  
    90. Marshal.FreeHGlobal(buffer);  
    91. return (TestStruct)retobj;  
    92. }        
    93. }  

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多