C#中的非安全編程(key:unsafe,fixed)

來源:互聯網
上載者:User
 原文地址http://www.cppblog.com/mzty/archive/2006/03/14/4126.html 本文將討論如何在C#中使用指標。

介紹
  這是C/C++程式迷們經常談論的一個話題,同時也是一個複雜的、難以理解的話題-指標!每次談到C#,大多數我遇到的人都持這樣的觀點-C#中沒有指標的概念。而實際上,它已經被廢除了,取而代之的是C#中的非安全編程-如何在程式中使用指標。不同於其字面意思的是,使用指標編程並沒有什麼不安全的。
  它如此受關注的根本原因是,非安全編程不同於習慣的.NET開發規範,而需要編程人員進行明確定本地環境設定(僅適用於本地執行)。本文我將從區別兩個最容易被疑惑的概念-非安全的程式碼與非受控代碼開始討論非安全編程這個主題。接下來我們將討論如何編寫非安全的程式碼,亦即如何在C#中使用指標。

非安全還是非受控?

受控代碼是指在CLR管理下執行的代碼。CLR負責了許多幕後的工作:

  • 管理對象的記憶體
  • 進行類型驗證
  • 記憶體回收

  說了這些,實際就是要將使用者從上述的這些工作中解脫出來了,專心於業務實現。使用者不再需要直接手工地進行記憶體操作,因為這些工作已由CLR完成了。
  另一方面,非受控代碼就是在CLR上下文外執行的代碼了。最好的例子就是我們平時使用的Win32 DLL,比如kernel32.dll,user32.dll以及安裝上我們系統上的各種COM組件。如何為它們分配記憶體、如何釋放這些記憶體、如何?類型驗證?這些工作都需要它們自己來完成。一個典型的C++程式中分配一個字元指標的語句也是非受控代碼的另一類例子,因為作為一名編程者,你要負責:

  • 調用記憶體配置函數
  • 確保類型轉換的結果正確
  • 確保指標在使用完畢後其記憶體被釋放

如果你留心上面的解釋,所有這些工作都是由CLR來完成以減輕編程者的負擔。

非安全的程式碼是介於受控與非受控代碼間的一種代碼類型

  非安全的程式碼仍然象受控代碼一樣是在CLR的管理下執行的,但在同時它又象非受控代碼一樣允許你通過指標直接存取記憶體。因此你獲得了兩者的優點。如果你正在編寫寫一個.NET應用程式,但同時又希望可以廣泛使用Win32 DLL中的各種函數-需要使用指標的,那麼此時非安全的程式碼就是你的救星了。
  我們已經明確了兩者的區別後,就開始編寫實際的代碼,毫無疑問,這才是最精彩的部分,你還在想什麼呢?

深入非安全的程式碼
  編寫非安全的程式碼需要使用特殊的關鍵字unsafefixed。如果你還記得的話,有三種指標操作符:

  • *
  • &
  • ->

  任何使用了上述任一指標操作符的語句、語句塊或者函數都應用unsafe關鍵字標記為非安全的程式碼,就象這樣:

public unsafe void Triple(int *pInt){  *pInt=(*pInt)*3;}

  上面這個函數只是將傳入的參數的值擴大了兩倍。但是請注意,傳入的是這個參數的指標!因為這個函數使用了"*"操作符直接進行記憶體操作,因此被標記為 unsafe
  但是這裡還是有一個問題。回想一下上面的討論,非安全的程式碼也是在CLR管理下的受控代碼,CLR可以自由地將對象移入記憶體中。於是一個似是而非的原因可能導致記憶體流失。這樣做的結果是,對於編程者可能在自覺不自覺中使這個變數的指標指向記憶體的其他地方。
  因此假設*pInt指向的地址是1001,而CLR的記憶體重定位過程將會引發記憶體流失。pInt之前指向1001,在重定位後其指向的資料可能被儲存在地址2003處。於是大禍臨頭了!pInt指向的1001處儲存的資料在經過重定位過程後無效了。這也許就是.NET很少提及指標的使用的原因吧,你認為呢?

固定指標
  在語句塊前輸入關鍵字fixed,將會告訴CLR塊內的對象不能重定位,這樣CLR就不會重定位指標指向的資料存放區位置。因此在C#中使用指標時,使用關鍵字fixed將能阻止程式運行時無效指標的產生。讓我們看看它是如何工作的:

using System;class CData{    public int x;}class CProgram{    unsafe static void SetVal(int *pInt)    {        *pInt=1979;    }        public unsafe static void Main()    {        CData d = new CData();                Console.WriteLine("Previous value: {0}", d.x);                fixed(int *p=&d.x)        {            SetVal(p);        }                Console.WriteLine("New value: {0}", d.x);    }}

  我們在這段代碼裡通過一個fixed塊,將CData對象資料成員(域)x的地址賦給了一個整數型指標p。當fixed塊中的語句被執行時,這個指標p將一直指向原來的那塊記憶體地區,因為CLR已被指示暫時凍結這個變數直到該fixed塊執行完畢。一旦fixed塊執行完畢,這個對象就又能被CLR重新置放了。
  以上就是C#中使用指標編程的介紹,關鍵是要說明語句塊是 unsafe 並 fixed 的。希望能因此提高你對C#中指標使用的知識!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.