Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
将C#void*转换为字节[]_C#_Pointers_Unmanaged_Unsafe - Fatal编程技术网

将C#void*转换为字节[]

将C#void*转换为字节[],c#,pointers,unmanaged,unsafe,C#,Pointers,Unmanaged,Unsafe,在C#中,我需要将T[]写入流,理想情况下不需要任何额外的缓冲区。我有一个动态代码,可以将T[](其中T是一个无对象结构)转换为void*并在内存中修复它,这非常有效。当流是一个文件时,我可以使用本机Windows API直接传递void*,但现在我需要写入一个接受字节[]的通用流对象 问:有人能建议一种黑客方法来创建一个虚拟数组对象,它实际上没有任何堆分配,而是指向一个已经存在(和固定)的堆位置吗 这是我需要的伪代码: void Write(Stream stream, T[] buffer)

在C#中,我需要将T[]写入流,理想情况下不需要任何额外的缓冲区。我有一个动态代码,可以将T[](其中T是一个无对象结构)转换为void*并在内存中修复它,这非常有效。当流是一个文件时,我可以使用本机Windows API直接传递void*,但现在我需要写入一个接受字节[]的通用流对象

问:有人能建议一种黑客方法来创建一个虚拟数组对象,它实际上没有任何堆分配,而是指向一个已经存在(和固定)的堆位置吗

这是我需要的伪代码:

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 );
    }
}  
void写入(流,T[]缓冲区)
{
修复(void*ptr=&buffer)//使用动态代码生成完成
{
int typeSize=sizeof(T);//也完成

字节[]伪=(字节[])因为流不能写一个指针,你不能避免复制内存,所以你会有一些减速。你可能想考虑使用一个BialRead和BinaryWriter来序列化你的对象,但是这里的代码会让你做你想做的事。记住T的所有成员也必须是结构。< /P>
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();
}
不安全的静态无效写入(流,T[]缓冲区),其中T:struct
{
System.Runtime.InteropServices.GCHandle handle=System.Runtime.InteropServices.GCHandle.Alloc(缓冲区,System.Runtime.InteropServices.GCHandleType.pinted);
IntPtr address=handle.addrofPindedObject();
int byteCount=System.Runtime.InteropServices.Marshal.SizeOf(typeof(T))*buffer.Length;
字节*ptr=(字节*)地址.ToPointer();
字节*endPtr=ptr+字节计数;
while(ptr!=endPtr)
{
stream.WriteByte(*ptr++);
}
handle.Free();
}

这种代码永远不会以通用方式工作。它依赖于一个硬假设,即T的内存布局是可预测的和一致的。只有当T是一个简单的值类型时,这才是正确的。暂时忽略endianness。如果T是引用类型,你就死在水中了,你将复制一个永远不会被删除的跟踪句柄因此,您必须为T提供struct约束

但这还不够,结构类型也不可复制。即使它们没有引用类型字段,这也是无法约束的。内部布局由JIT编译器决定。它可以随意交换字段,选择一个字段对齐且结构值采用最小存储大小的字段。v要序列化的值只能由使用完全相同的CPU体系结构和JIT编译器版本运行的程序正确读取


框架中已经有很多类可以执行您正在执行的操作。最匹配的类是.NET 4.0 MemoryMappedViewAccessor类。它需要执行相同的任务,使内存映射文件中的原始字节可用。这里的主力是System.Runtime.InteropServices.SafeBuffer类,请查看Reflector.Unfo当然,你不能只是复制类,它依赖CLR来进行转换。不过,再过一周它就可以使用了。

查看我对相关问题的回答:

在其中,我临时将一个浮点数组转换为一个字节数组,而不进行内存分配和复制。 为此,我使用内存操作更改了CLR的元数据


不幸的是,此解决方案不适合泛型。但是,您可以将此技术与代码生成技术相结合来解决您的问题。

看看这篇文章,这是获得理想代码的最佳方法:)

Jeff,Marshall。复制速度慢得令人难以置信,而且很容易避免。我在我总是可以创建一个字节[],并使用我的方法快速将字节从一个固定的ptr复制到另一个ptr,然后将该数组发送到流,但我希望避免不必要的分配和复制。编辑,虽然我不确定一次写入一个字节将如何执行.NET 4.0,但我会选择nobugz答案,否则我认为这可能与您得到的预处理结果一样好.NET 4.0…你应该看看BinarySerializer类。@Joel-如果你是说
BinaryFormatter
,我会坚决反对它;-pNobugz,谢谢你提供的所有4.0信息-我会深入研究它。至于T-my代码只检查struct,没有ref类型,无论是显式的还是顺序的pack1结构。这应该会考虑到所有iss您提出的ues。请查看工作实现。如果这已经起作用,那么问题的重点是什么?垃圾邮件?不,当然不是:)。我只能修复堆中的T数组并获得一个void*,这在使用mem映射文件或其他win API时非常好。它不适用于任何使用byte[]的方法.Omer:您的技术在这里不起作用,因为它需要元数据。如果您有一个指向内存映射文件的
void*
,则在不修改文件内容的情况下无法在那里获取元数据。