2010-10-12 67 views
2

我想創建一個屬性,將從我的字節數組(字節[]),使指針(字節*),這的確行得通,但是每當我修改這個返回的指針,我的字節數組不會被修改,這是我想要使用的一段代碼。一個字節[]到字節*屬性

public unsafe class PacketWriter 
{ 
    private readonly byte[] _packet; 
    private int _position; 

    public byte* Pointer 
    { 
     get 
     { 
      fixed (byte* pointer = _packet) 
       return pointer; 
     } 
    } 

    public PacketWriter(int packetLength) 
    { 
     _packet = new byte[packetLength]; 
    } 

    //An example function 
    public void WriteInt16(short value) 
    { 
     if (value > Int16.MaxValue) 
      throw new Exception("PacketWriter: You cannot write " + value + " to a Int16."); 
     *((short*)(Pointer + _position)) = (short) value; 
     _position += 2; 
    } 

    //I would call this function to get the array. 
    public byte[] GetPacket 
    { 
     get { return _packet; } 
    } 
} 

而且,我知道我可以簡單地刪除屬性,並把函數內部的代碼,這可能會工作,但是我試圖找出一種方法使用屬性來做到這一點 - 除非這會降低性能在這種情況下,請讓我知道。

+1

你爲什麼要這樣做,而不是簡單地使用普通數組? – 2010-10-12 13:52:14

+1

當垃圾收集器移動陣列時,此代碼將炸彈或無聲地破壞堆。在屬性獲取器返回後,該數組不再固定。賠率低但不爲零。 – 2010-10-12 15:09:16

+0

它只是讓我感到你正在編寫可能用於網絡通信的代碼,你可能想要保留網絡字節順序。在這種情況下,我建議在MemoryStream上使用BinaryReader和BinaryWriter,因爲這些可以指定編碼的字節順序。您提出的代碼和BitConverter都將使用平臺端到端。 – 2010-10-14 03:09:04

回答

6

在這裏使用指針(在C#中)是毫無意義的。

請注意,如果您有

public byte[] Data { get { return _packet; } } 

更換Pointer財產您必須返回參考的字節數組的屬性,它可以讓你做同樣的編輯在陣列中的一個指針,而無需在任何時候複製數組。

而另一條建議,在你Write16,使用:

byte[] data = BitConverter.GetBytes(value); 
data.CopyTo(_packet, _positiion); 
_position += data.Length; 
+0

+1,BitConverter是將字節等價物寫入數組(它使用平臺排序)的最乾淨和最平臺安全的方式。 – 2010-10-12 14:43:10

2

當您的控件離開fixed(並且它在返回後立即執行)後,您的對象不再被鎖定。所以它只在fixed內有效

+0

@Andrey,有沒有不同的方式來實現我的目標? – Basser 2010-10-12 13:41:46

+0

@Basser使用C++ :)你應該在功能範圍內使用'fixed'。財產訪問將不起作用。我沒有理由在這裏使用'byte *',指針在C#中是例外的,並且需要特殊情況。這一個絕對不是。 – Andrey 2010-10-12 13:44:21

+0

@Basser,你的目標是什麼?你想用指針做什麼? – testalino 2010-10-12 13:45:24

0

如果你正在處理被管理的內存,那麼是的,你必須限制它到fixed塊。

看起來你正在使用大量的指針處理,我的問題是爲什麼你需要一個託管內存?只需使用Marshal.AllocHGlobal()分配一些非託管內存,然後將其作爲指針公開。你只需要確保你在Dispose()中發佈它。

2

不要讓指針。 你在搶先優化你的代碼。爲了舉一個例子,我在C#中爲我正在開發的一個項目編寫了一個PNG解碼器,而不是假設這個瓶頸,我編寫了代碼來使管理數據結構變得微不足道,並且相當關注I/O和數據運動。在對代碼進行基準測試時,瓶頸不在數據移動或I/O中,而是在Paeth預測器中 - 計算以像素爲單位進行(詳細信息請參見here)。

首先編寫可讀和可維護的代碼,然後查看瓶頸位置。你可以隨時重構它。

1

在.NET中對數組索引非常有效;抖動產生的機器代碼基本上等同於通過指針算術訪問。如果您編寫使用位掩碼和位移來生成寫入數組的字節值的等效代碼,它可能會比嘗試使用不安全的代碼更快。釘扎的開銷將遠遠高於一些廉價的位掩蔽操作。如果你真的,絕對需要節省幾個時鐘週期(以降低可維護性爲代價的昂貴代價),要麼在C++中創建一個非託管DLL來處理高性能需求,要麼編寫完全在非託管內存中操作的純不安全代碼與元帥。事實上,元帥已經有了一個可以使用的WriteInt16方法。然而,封送到託管內存的開銷會比較高,但是(比位掩碼高得多),所以這隻有在您在內部循環中編寫大量內存並且正在執行其他操作時纔有用除了簡單的複製操作(因爲無論如何它都必須複製到託管內存來編組)。