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.
我有一个表示有线格式数据包的结构。在这种结构中是一系列其他结构。我有通用代码,在大多数情况下处理这个非常好,但这个结构数组的情况是抛出marshaller循环。
Unsafe code is a no go since I can't get a pointer to a struct with an array (argh!).
不安全的代码是不行的,因为我无法获得指向带有数组的结构的指针(argh!)。
I can see from this codeproject article that there is a very nice, generic approach involving C++/CLI that goes something like...
我可以从这个代码项目文章中看到,有一个非常好的,通用的方法涉及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!
现在,如果只有结构 - >字节数组/写入器版本我将被设置!提前致谢!
5 个解决方案
#1
2
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;
}
};
#2
1
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.
实际上,可以使用不安全的代码来执行此操作。请参阅我从磁盘读取结构的帖子:从C#中的文件读取数组而无需额外的副本。
#3
0
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.
感谢psuedocode悲伤,我会看看它是否完成了工作并报告回来。
#4
0
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语言,则应该没有问题,否则,您应该能够将指针放在不安全的代码中并通过逐个指向的元素(使用不安全的代码)并添加来初始化新数组他们对它。
#5
0
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类型的内存布局。
#1
2
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;
}
};
#2
1
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.
实际上,可以使用不安全的代码来执行此操作。请参阅我从磁盘读取结构的帖子:从C#中的文件读取数组而无需额外的副本。
#3
0
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.
感谢psuedocode悲伤,我会看看它是否完成了工作并报告回来。
#4
0
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语言,则应该没有问题,否则,您应该能够将指针放在不安全的代码中并通过逐个指向的元素(使用不安全的代码)并添加来初始化新数组他们对它。
#5
0
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类型的内存布局。