c# 如何 使用共用體
阿新 • • 發佈:2017-11-01
文件輸入 地址 jsb fse 什麽 簡單 int namespace blank
用起來真的方便 轉摘如下:
C#借助FieldOffset屬性實現共用體與強制類型轉換
這兩天被C#的強制類型轉換弄得有點不習慣。事出如此。
在C#中,我打算讀二進制文。文件的結構很簡單,一連串的緊密存儲的int32值,以二進制方式存放。現在我希望隨機讀取第n個int32開始的i個值,並讀入到數組中。結果查一下C#只能讀到byte[]中,要不就是一個個讀出來循環放int[]。追求效率的我當然不希望這樣,如果能像C++那樣將byte[]強制轉換成int[]就好了。例如:
[cpp] view plain copy print?
- char tmp[64]; // 16個int。相當於C#的 byte[] tmp = new int[64];
- int* dat; // dat的指針。相當於C#的 int[] dat;
- ifstream IF(...); // 標準文件輸入流。相當於C#的 FileStream FS = new FileStream(...);
- IF.read(tmp, 64); // 讀取64個字節。 相當於C#的 FS.Read(tmp,0,64);
- dat = (int*)tmp; // 將tmp數組的首地址轉為int類型,則數組以4個字節為一個int轉換為int型的數組。
- // 數據在內存上沒有任何變化,因為數據本來就是int型的。
- // 關鍵是這一步在C#中無法直接實現。
- for (int i = 0; i < 16; i++)
- cout << dat[i] << " "; // 輸出數據。相當於C#的 Console.Write(dat[i]+" ");
在C#中無法直接實現,為此我想了好些辦法,也查了好久,直到我見到了這樣的代碼:
[csharp] view plain copy print?
- using System;
- using System.IO;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- // 提供各種各樣支持 COM 互操作 及平臺調用服務的成員
- using System.Runtime.InteropServices;
- namespace test
- {
- class Program
- {
- // StructLayout使設計者可以控制類或結構的數據字段的物理布局
- // Explicit與FieldOffset一起可以控制每個數據成員的精確位置
- [StructLayout(LayoutKind.Explicit)]
- public struct S1
- {
- // FieldOffset控制字段所在的物理位置偏移為0
- [FieldOffset(0)]
- public byte[] a;
- // 同樣偏移為0,開始位置與a重疊了。
- [FieldOffset(0)]
- public int[] b;
- }
- static void Main(string[] args)
- {
- S1 s = new S1(); // 要new,不然b會報“使用了可能未賦值的字段”
- s.a=new byte[64];
- FileStream FS = new FileStream("E:\\test.txt", FileMode.Open);
- // 以s.a來接收文件的數據
- FS.Read(s.a,0,64);
- // 自己保證讀b的時候不要越界
- for (int i = 0; i < 16; i++)
- Console.Write(s.b[i]+" "); // 以b來使用數據
- Console.ReadKey();
- }
- }
- }
原理實際上跟C++一樣,將一個int[]型的變量指向與byte[]型變量相同的內存區域,跟C++中將dat指向char數組的首地址是一樣的。同樣,這樣的結構體功能與C++的共用體是一樣的,即一個結構可以作為多種數據類型,而具體是什麽類型視情況而定。
測試所使用的文件就不上傳了,有WinHex的可以自己編輯一個,沒有的也可以寫程序將從0xF到0x0的16個數以二進制方式輸出到文件中。文件的內容用WinHex打開以16進制顯示應該如下:
c# 如何 使用共用體