C# C++ CLI 结构到字节数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/330043/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C++ CLI structure to byte array
提问by JasonCoder
I have a structure that represents a wire format packet. In this structure is an array of other structures. I have generic code that handles this very nicely for most cases but this array of structures case is throwing the marshaller for a loop.
我有一个表示有线格式数据包的结构。在这个结构中是其他结构的数组。我有通用代码可以在大多数情况下很好地处理这个问题,但是这个结构数组案例正在为循环抛出编组器。
Unsafe code is a no go since I can't get a pointer to a struct with an array (argh!).
不安全的代码是不行的,因为我无法获得指向带有数组的结构的指针(啊!)。
I can see from this codeproject articlethat there is a very nice, generic approach involving C++/CLI that goes something like...
我可以从这篇 codeproject 文章中看到,有一个非常好的通用方法,涉及 C++/CLI,类似于...
public ref class Reader abstract sealed
{
public:
generic <typename T> where T : value class
static T Read(array<System::Byte>^ data)
{
T value;
pin_ptr<System::Byte> src = &data[0];
pin_ptr<T> dst = &value;
memcpy((void*)dst, (void*)src,
/*System::Runtime::InteropServices::Marshal::SizeOf(T::typeid)*/
sizeof(T));
return value;
}
};
Now if just had the structure -> byte array / writer version I'd be set! Thanks in advance!
现在,如果只有结构 -> 字节数组/编写器版本,我会被设置!提前致谢!
回答by grieve
Using memcpy to copy an array of bytes to a structure is extremely dangerous if you are not controlling the byte packing of the structure. It is safer to marshall and unmarshall a structure one field at a time. Of course you will lose the generic feature of the sample code you have given.
如果您不控制结构的字节打包,则使用 memcpy 将字节数组复制到结构中是极其危险的。一次一个字段编组和解组结构更安全。当然,您将失去所提供的示例代码的通用功能。
To answer your real question though (and consider this pseudo code):
不过要回答你真正的问题(并考虑这个伪代码):
public ref class Writer abstract sealed
{
public:
generic <typename T> where T : value class
static System::Byte[] Write(T value)
{
System::Byte buffer[] = new System::Byte[sizeof(T)]; // this syntax is probably wrong.
pin_ptr<System::Byte> dst = &buffer[0];
pin_ptr<T> src = &value;
memcpy((void*)dst, (void*)src,
/*System::Runtime::InteropServices::Marshal::SizeOf(T::typeid)*/
sizeof(T));
return buffer;
}
};
回答by Mehrdad Afshari
This is probably not the right way to go. CLR is allowed to add padding, reorder the items and alter the way it's stored in memory.
这可能不是正确的方法。CLR 可以添加填充、重新排序项目并改变它在内存中的存储方式。
If you want to do this, be sure to add [System.Runtime.InteropServices.StructLayout]
attribute to force a specific memory layout for the structure. In general, I suggest you not to mess with memory layout of .NET types.
如果你想这样做,一定要添加[System.Runtime.InteropServices.StructLayout]
属性来强制结构的特定内存布局。一般来说,我建议你不要搞乱 .NET 类型的内存布局。
回答by JasonCoder
Not altering the structure is certainly sound advice. I use liberal amounts of StructLayout attributes to specify the packing, layout and character encoding. Everything flows just fine.
不改变结构当然是合理的建议。我使用大量的 StructLayout 属性来指定打包、布局和字符编码。一切都很好。
My issue is just that I need a performant and preferably generic solution. Performance because this is a server application and generic for elegance. If you look at the codeproject link you'll see that the StructureToPtr and PtrToStructure methods perform on the order of 20 times slower than a simple unsafe pointer cast. This is one of those areas where unsafe code is full of win. C# will only let you have pointers to primitives (and it's not generic - can't get a pointer to a generic), so that's why CLI.
我的问题只是我需要一个高性能且最好是通用的解决方案。性能,因为这是一个服务器应用程序和通用的优雅。如果您查看 codeproject 链接,您将看到 StructureToPtr 和 PtrToStructure 方法的执行速度比简单的不安全指针转换慢 20 倍。这是不安全代码充满胜利的领域之一。C# 只会让您拥有指向原语的指针(并且它不是通用的 - 无法获得指向通用的指针),这就是 CLI 的原因。
Thanks for the psuedocode grieve, I'll see if it gets the job done and report back.
感谢您的伪代码悲伤,我会看看它是否能完成工作并报告回来。
回答by jheriko
Am I missing something? Why not create a new array of the same size and initialise each element seperately in a loop?
我错过了什么吗?为什么不创建一个相同大小的新数组并在循环中单独初始化每个元素?
Using an array of byte data is quite dangerous unless you are targetting one platform only... for example your method doesn't consider differing endianness between the source and destination arrays.
除非您仅针对一个平台,否则使用字节数据数组非常危险……例如,您的方法不考虑源数组和目标数组之间的不同字节顺序。
Something I don't really understand about your question as well is why having an array as a member in your class is causing a problem. If the class comes from a .NET language you should have no issues, otherwise, you should be able to take the pointer in unsafe code and initialise a new array by going through the elements pointed at one by one (with unsafe code) and adding them to it.
关于您的问题,我也不太明白为什么将数组作为类中的成员会导致问题。如果该类来自 .NET 语言,您应该没有问题,否则,您应该能够在不安全代码中获取指针并通过逐个遍历指向的元素(使用不安全代码)并添加来初始化一个新数组他们给它。
回答by jheriko
Unsafe code can be made to do this, actually. See my post on reading structs from disk: Reading arrays from files in C# without extra copy.
实际上,可以编写不安全的代码来执行此操作。请参阅我关于从磁盘读取结构的帖子:Reading array from files in C# without extra copy。