轉(zhuǎn)帖|其它|編輯:郝浩|2011-07-28 15:23:09.000|閱讀 1475 次
概述:在C/C++中,對于指針的使用是很普遍的,可以這么說,如果沒有指針的運用,都不知道程序如何來寫。在.Net中,同樣也是可以使用指針的,不過必須通 過開啟不安全的代碼來使用。在默認情況下,新建的項目是不允許使用不安全的代碼,這樣,就必須通過設置項目來開啟使用,通過設置項目“屬性”的“生成”來 達到:
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
在C/C++中,對于指針的使用是很普遍的,可以這么說,如果沒有指針的運用,都不知道程序如何來寫。在.Net中,同樣也是可以使用指針的,不過必須通 過開啟不安全的代碼來使用。在默認情況下,新建的項目是不允許使用不安全的代碼,這樣,就必須通過設置項目來開啟使用,通過設置項目“屬性”的“生成”來 達到:
勾選“允許不安全代碼”的選項就OK了。
1、unsafe
要使用指針,還不必須在你的方法體或者是某個作用域中添加unsafe關(guān)鍵字,如:
unsafe static void Main(string[] args)
{
// 不安全代碼編寫
}
或者:
unsafe
{
// 不安全代碼編寫
}
2、stackalloc
關(guān)鍵字stackalloc是用于申請棧內(nèi)存。stackalloc類似于C庫中的_alloca。通過使用stackalloc可以自動啟用CLR中的緩沖區(qū)溢出檢測功能。當函數(shù)執(zhí)行完畢后,內(nèi)存會被自動回收。
使用它的目的通過它來實現(xiàn)對棧內(nèi)存的使用,從而減少對堆的使用,減少系統(tǒng)開銷。
如下參考程序:
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的數(shù)據(jù)存在堆中,這里通過指針的方式減少系統(tǒng)的開銷。
3、IntPtr 和 ref
IntPtr是.Net提供的托管指針,ref是C#語言中的關(guān)鍵字,和IntPtr沒有關(guān)系,盡管它們使用起來很類似。區(qū)別在于,使用ref可以引用Class,共同點它們都可以引用值類型,包括Struct結(jié)構(gòu)體等等。
接著,編寫一個Struct結(jié)構(gòu)體:
[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)交易貨幣指數(shù)*/
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] szRefCurrCode_n_9F3C; /** <(TERM)交易參考貨幣代碼*/
public byte cRefCurrExp_n_9F3D; /** <(TERM)交易參考貨幣指數(shù)*/
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] szRefRate_n; /** <(TERM)交易參考貨幣兌換比率*/
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] szIFD_an_9F1E; /** <(TERM)接口設備(IFD)序列號*/
}
這里我引用項目中的一個結(jié)構(gòu)體,具體字段不多說了,就是一些為字節(jié)數(shù)字的參數(shù)字段。另外MarshalAs特性可以設置非托管數(shù)組時的長度。
為了方便,這里編寫一個初始化的結(jié)構(gòu)體:
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();
獲取它的句柄,也就是指針I(yè)ntPtr:
int size = Marshal.SizeOf(para);
IntPtr intPtr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(para, intPtr, true);
byte* bytes = (byte*)intPtr.ToPointer();
通過對于bytes指針的內(nèi)存地址的遍歷:
for (int index = 0; index < size; index++)
{
Console.Write(*(bytes + index) + ",");
}
寫法是不是和C指針的寫法一樣呢。運行結(jié)果,可以輸出初始化的值。
比較函數(shù)調(diào)用,數(shù)據(jù)傳遞效率:
編寫測試程序:
CodeTimer.Time("結(jié)構(gòu)體的數(shù)據(jù)傳遞", 10000000, () => { GetValue(para); });
CodeTimer.Time("結(jié)構(gòu)體Ref的數(shù)據(jù)傳遞", 10000000, () => { GetValue(ref para); });
CodeTimer.Time("結(jié)構(gòu)體IntPtr的數(shù)據(jù)傳遞", 10000000, () => { GetValue(intPtr); });
其中:
static void GetValue(ST_TERMPARA para)
{
// ...
}
static void GetValue(ref ST_TERMPARA para)
{
// ...
}
static void GetValue(IntPtr intPtr)
{
// ...
}
運行結(jié)果:
從結(jié)果上看,結(jié)構(gòu)體的直接傳遞耗時最長,因為Struct是個值類型,在進行函數(shù)傳值時,會在參數(shù)上拷貝一份新的Struct對象,而結(jié)構(gòu)體ref 的數(shù)據(jù)傳遞,由于只需要傳遞引用該結(jié)構(gòu)體的“指針”,而IntPtr同樣本身作為結(jié)構(gòu)體的指針,所以效率上后兩者比第一個要高。
另外,從多次的運行結(jié)果上來看,Ref比IntPtr的傳遞效率總是高一些,至于為什么,不是很了解其中的機制,看哪些朋友能夠給我些指點,感謝。
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請務必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:網(wǎng)絡轉(zhuǎn)載