2015-05-29 87 views
2

我最近通過文章image processing in C#使不安全的代碼在C#安全

閱讀有一個在那裏,我真的不喜歡,因爲它是不安全的,我想一些代碼知道它是否能進行安全:

public static bool Invert(Bitmap b) 
{ 
    // GDI+ still lies to us - the return format is BGR, NOT RGB. 
    BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), 
     ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); 
    int stride = bmData.Stride; 
    System.IntPtr Scan0 = bmData.Scan0; 
    unsafe 
    { 
     byte * p = (byte *)(void *)Scan0; 
     int nOffset = stride - b.Width*3; 
     int nWidth = b.Width * 3; 
     for(int y=0;y < b.Height;++y) 
     { 
      for(int x=0; x < nWidth; ++x) 
      { 
       p[0] = (byte)(255-p[0]); 
       ++p; 
      } 
      p += nOffset; 
     } 
    } 

    b.UnlockBits(bmData); 

    return true; 
} 

byte* p = (byte*)(void*)Scan0;模樣的罪魁禍首,但我不得不說,我真的不明白它在做什麼,或者它如何可以作出安全。

任何人都可以對此有所瞭解嗎?

+8

如果你不知道它在做什麼,爲什麼你想「讓它安全」?你害怕「不安全」這個詞嗎?該代碼用於使用指針直接訪問內存中的位圖像素。另一種方法是使用GetPixel()來編組每個像素的數據,速度非常慢。 – CodeCaster

+0

'Scan0'是一個'IntPtr',所以如果你想獲得相同的處理速度,你基本上必須使用指針。 –

+1

「我怎樣才能讓它不安全?」 - 停止使用指針。如果你不知道_why_它的使用標記,那麼就不要惹它(或找到某人知道它在做什麼和_why_)。 –

回答

5

不安全的代碼主要用於性能方面的原因。基本思想是你要逐字節地遍歷圖像數據,並手動翻轉每個字節(雖然有更高效和簡單的方法來處理相同的事情)。

底層圖像由GDI +處理,這是非託管代碼。所以當你直接使用圖像字節時,你必須操縱非託管內存。這是多麼安全或不安全確實是令人驚訝的棘手 - 它取決於非託管內存最初如何分配。假設您使用託管代碼工作,並且您可能從文件或某個流中加載了位圖,實際上它可能並不真正不安全 - 例如,您無法意外覆蓋託管內存。 unsafe關鍵字的名稱並不是來自固有的危險 - 它來自允許你做非常不安全的事情。例如,如果您在自己的託管堆棧上爲位圖分配了內存,則可能會讓事情變得糟糕。

總的來說,如果你真的能證明它是值得的成本,那麼只使用不安全的代碼是一個好習慣。在圖像處理中,這通常是一個很好的折衷 - 您正在處理大量簡單的數據,其中的開銷例如邊界檢查可能很重要,即使只能驗證一次,而不是在每個循環的迭代中都很容易。

如果你想擺脫這種不安全的代碼,一個辦法是分配自己byte[](管理),使用Marshal.Copy將圖像數據複製到這個byte[],做管理的陣列中所做的修改,然後再複製結果再次使用Marshal.Copy。問題是,這意味着分配一個與原始圖像一樣大的byte[],然後將其複製兩次(在這種情況下邊界檢查可以忽略不計 - .NET JIT編譯器會優化它)。最後,它仍然是可能的在使用Marshal.Copy時會出現錯誤,這會給您帶來與unsafe相同的問題(不完全是這樣,但這將會花費更長的時間)。

對我而言,unsafe作爲關鍵字的最有價值的部分是它可以讓你本地化你正在做的不安全的東西。雖然典型的非託管應用程序是不安全的,但C#只允許您在代碼的特定標記部分中不安全。雖然這些仍然會影響其他代碼(這是在FullTrust環境中只能使用unsafe的原因之一),但它使它們更易於調試和控制。這是一個權衡,一如既往。

但是,代碼實際上是以非常不同的方式不安全的 - 如果在代碼的中間存在異常,則可能永遠不會發生調用UnlockBits。您應該使用finally子句確保properrer清理非託管資源。

最後,如果你想要「真正」的性能,安全或不安全,你可能不會在CPU上進行圖像處理。今天,假設您正在運行的計算機具有GPU,可以更快,更輕鬆地完成工作,並且完全與計算機本身運行的代碼完全隔離,這往往是安全的。