轉帖|其它|編輯:郝浩|2011-07-28 15:23:09.000|閱讀 1482 次
概述:在C/C++中,對于指針的使用是很普遍的,可以這么說,如果沒有指針的運用,都不知道程序如何來寫。在.Net中,同樣也是可以使用指針的,不過必須通 過開啟不安全的代碼來使用。在默認情況下,新建的項目是不允許使用不安全的代碼,這樣,就必須通過設置項目來開啟使用,通過設置項目“屬性”的“生成”來 達到:
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
在C/C++中,對于指針的使用是很普遍的,可以這么說,如果沒有指針的運用,都不知道程序如何來寫。在.Net中,同樣也是可以使用指針的,不過必須通 過開啟不安全的代碼來使用。在默認情況下,新建的項目是不允許使用不安全的代碼,這樣,就必須通過設置項目來開啟使用,通過設置項目“屬性”的“生成”來 達到:
勾選“允許不安全代碼”的選項就OK了。
1、unsafe
要使用指針,還不必須在你的方法體或者是某個作用域中添加unsafe關鍵字,如:
unsafe static void Main(string[] args)
{
// 不安全代碼編寫
}
或者:
unsafe
{
// 不安全代碼編寫
}
2、stackalloc
關鍵字stackalloc是用于申請棧內存。stackalloc類似于C庫中的_alloca。通過使用stackalloc可以自動啟用CLR中的緩沖區溢出檢測功能。當函數執行完畢后,內存會被自動回收。
使用它的目的通過它來實現對棧內存的使用,從而減少對堆的使用,減少系統開銷。
如下參考程序:
int* array = stackalloc int[10];
for (int index = 0; index < 10; index++)
{
array[index] = index;
}
for (int index = 0; index < 10; index++)
{
Console.WriteLine(array[index].ToString());
}
代替了程序:int[] array = new int[10]; 等同于System.Array的數據存在堆中,這里通過指針的方式減少系統的開銷。
3、IntPtr 和 ref
IntPtr是.Net提供的托管指針,ref是C#語言中的關鍵字,和IntPtr沒有關系,盡管它們使用起來很類似。區別在于,使用ref可以引用Class,共同點它們都可以引用值類型,包括Struct結構體等等。
接著,編寫一個Struct結構體:
[StructLayout(LayoutKind.Sequential)]
public struct ST_TERMPARA
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public byte[] szAcqID_n_9F01; /** <(TERM)收單行標識*/
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public byte[] szAddTermCap_b_9F40; /** <(TERM)附加終端性能*/
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] szMerCateCode_n_9F15; /** <(TERM)商戶分類碼*/
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)]
public byte[] szMerID_ans_9F16; /** <(TERM)商戶標識*/
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
public byte[] szMerNameLoc_ans; /** <(TERM)商戶名稱和位置*/
public byte cMessageType_n; /** <(TERM)報文類別*/
public byte cEntryMode_n_9F39; /** <(TERM)銷售點(POS)輸入方式*/
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] szTermCap_b_9F33; /** <(TERM)終端性能*/
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] szTermCountryCode_b_9F1A; /** <(TERM)終端國家代碼*/
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] szTermId_an_9F1C; /** <(TERM)終端號*/
public byte cTypeTerm_n_9F35; /** <(TERM)終端類型*/
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] szCurCode_n_5F2A; /** <(TERM)交易貨幣代碼*/
public byte cCurExp_n_5F36; /** <(TERM)交易貨幣指數*/
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] szRefCurrCode_n_9F3C; /** <(TERM)交易參考貨幣代碼*/
public byte cRefCurrExp_n_9F3D; /** <(TERM)交易參考貨幣指數*/
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] szRefRate_n; /** <(TERM)交易參考貨幣兌換比率*/
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] szIFD_an_9F1E; /** <(TERM)接口設備(IFD)序列號*/
}
這里我引用項目中的一個結構體,具體字段不多說了,就是一些為字節數字的參數字段。另外MarshalAs特性可以設置非托管數組時的長度。
為了方便,這里編寫一個初始化的結構體:
ST_TERMPARA para;
para.szAcqID_n_9F01 = Enumerable.Repeat<byte>(0x01, 6).ToArray();
para.szAddTermCap_b_9F40 = Enumerable.Repeat<byte>(0x02, 5).ToArray();
para.szMerCateCode_n_9F15 = Enumerable.Repeat<byte>(0x03, 2).ToArray();
para.szMerID_ans_9F16 = Enumerable.Repeat<byte>(0x04, 15).ToArray();
para.szMerNameLoc_ans = Enumerable.Repeat<byte>(0x05, 40).ToArray();
para.cMessageType_n = 0x06;
para.cEntryMode_n_9F39 = 0x07;
para.szTermCap_b_9F33 = Enumerable.Repeat<byte>(0x08, 3).ToArray();
para.szTermCountryCode_b_9F1A = Enumerable.Repeat<byte>(0x09, 2).ToArray();
para.szTermId_an_9F1C = Enumerable.Repeat<byte>(0x0a, 8).ToArray();
para.cTypeTerm_n_9F35 = 0x0b;
para.szCurCode_n_5F2A = Enumerable.Repeat<byte>(0x0c, 2).ToArray();
para.cCurExp_n_5F36 = 0x0d;
para.szRefCurrCode_n_9F3C = Enumerable.Repeat<byte>(0x0e, 2).ToArray();
para.cRefCurrExp_n_9F3D = 0x0f;
para.szRefRate_n = Enumerable.Repeat<byte>(0x10, 4).ToArray();
para.szIFD_an_9F1E = Enumerable.Repeat<byte>(0x10, 8).ToArray();
獲取它的句柄,也就是指針IntPtr:
int size = Marshal.SizeOf(para);
IntPtr intPtr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(para, intPtr, true);
byte* bytes = (byte*)intPtr.ToPointer();
通過對于bytes指針的內存地址的遍歷:
for (int index = 0; index < size; index++)
{
Console.Write(*(bytes + index) + ",");
}
寫法是不是和C指針的寫法一樣呢。運行結果,可以輸出初始化的值。
比較函數調用,數據傳遞效率:
編寫測試程序:
CodeTimer.Time("結構體的數據傳遞", 10000000, () => { GetValue(para); });
CodeTimer.Time("結構體Ref的數據傳遞", 10000000, () => { GetValue(ref para); });
CodeTimer.Time("結構體IntPtr的數據傳遞", 10000000, () => { GetValue(intPtr); });
其中:
static void GetValue(ST_TERMPARA para)
{
// ...
}
static void GetValue(ref ST_TERMPARA para)
{
// ...
}
static void GetValue(IntPtr intPtr)
{
// ...
}
運行結果:
從結果上看,結構體的直接傳遞耗時最長,因為Struct是個值類型,在進行函數傳值時,會在參數上拷貝一份新的Struct對象,而結構體ref 的數據傳遞,由于只需要傳遞引用該結構體的“指針”,而IntPtr同樣本身作為結構體的指針,所以效率上后兩者比第一個要高。
另外,從多次的運行結果上來看,Ref比IntPtr的傳遞效率總是高一些,至于為什么,不是很了解其中的機制,看哪些朋友能夠給我些指點,感謝。
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@ke049m.cn
文章轉載自:網絡轉載