簡體   English   中英

將C#void *轉換為byte []

[英]Converting C# void* to byte[]

在C#中,我需要將T []寫入流,理想情況下不需要任何額外的緩沖區。 我有一個動態代碼,將T [](其中T是無對象結構)轉換為void *並將其修復到內存中,並且效果很好。 當流是文件時,我可以使用本機Windows API直接傳遞void *,但現在我需要寫入一個帶有byte []的通用Stream對象。

問題:任何人都可以建議一種黑客方式來創建一個虛擬數組對象,它實際上沒有任何堆分配,而是指向已經存在(和固定)的堆位置?

這是我需要的偽代碼:

void Write(Stream stream, T[] buffer)
{
    fixed( void* ptr = &buffer )    // done with dynamic code generation
    {
        int typeSize = sizeof(T);   // done as well

        byte[] dummy = (byte[]) ptr;   // <-- how do I create this fake array?

        stream.Write( dummy, 0, buffer.Length*typeSize );
    }
}  

更新:我介紹了如何做fixed(void* ptr=&buffer)在深入這篇文章 我總是可以創建一個byte [],在內存中修復它,並從一個指針到另一個指針執行不安全的字節復制,然后將該數組發送到流中,但我希望避免不必要的額外分配和復制。

不可能? 進一步思考后,byte []在堆中有一些元數據,包括數組維度和元素類型。 簡單地將引用(指針)傳遞給T []作為byte []可能不起作用,因為塊的元數據仍然是T []的元數據。 即使元數據的結構相同,T []的長度也會遠小於byte [],因此托管代碼對byte []的任何后續訪問都會產生不正確的結果。

請求功能@ Microsoft Connect請投票支持此請求 ,希望MS能夠收聽。

這種代碼永遠不會以通用的方式工作。 它依賴於一種硬假設,即T的內存布局是可預測且一致的。 只有在T是簡單值類型時才會出現這種情況。 暫時忽略字節序。 如果T是引用類型,你就死在水中,你將復制永遠無法反序列化的跟蹤句柄,你必須給T結構約束。

但這還不夠,結構類型也不可復制。 即使他們沒有引用類型字段,也不能約束。 內部布局由JIT編譯器確定。 它在閑暇時交換字段,選擇字段正確對齊的字段,結構值采用最小存儲大小。 您將序列化的值只能由運行完全相同的CPU體系結構和JIT編譯器版本的程序正確讀取。

框架中已經有很多類可以完成你正在做的事情。 最接近的匹配是.NET 4.0 MemoryMappedViewAccessor類。 它需要做同樣的工作,在內存映射文件中提供原始字節。 主要的是System.Runtime.InteropServices.SafeBuffer類,看看有了Reflector。 不幸的是,你不能只復制類,它依賴於CLR來進行轉換。 再說一遍,它還有一周才可用。

看看這篇文章在C#/ VB.NET和Generic Pointers中使用內聯MSIL獲取夢想代碼的最佳方法:)

因為stream.Write不能占用指針,所以無法避免復制內存,因此會有一些減速。 您可能需要考慮使用BinaryReader和BinaryWriter來序列化您的對象,但這里的代碼可以讓您按照自己的意願行事。 請記住,T的所有成員也必須是結構。

unsafe static void Write<T>(Stream stream, T[] buffer) where T : struct
{
    System.Runtime.InteropServices.GCHandle handle = System.Runtime.InteropServices.GCHandle.Alloc(buffer, System.Runtime.InteropServices.GCHandleType.Pinned);
    IntPtr address = handle.AddrOfPinnedObject();
    int byteCount = System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)) * buffer.Length;
    byte* ptr = (byte*)address.ToPointer();
    byte* endPtr = ptr + byteCount;
    while (ptr != endPtr)
    {
        stream.WriteByte(*ptr++);
    }
    handle.Free();
}

看看我對相關問題的回答: 將float []轉換為byte []的最快方法是什么?

在其中我暫時將浮點數組轉換為字節數組而不進行內存分配和復制。 為此,我使用內存操作更改了CLR的元數據。

不幸的是,這種解決方案不適合仿制葯。 但是,您可以將此hack與代碼生成技術結合起來解決您的問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM