我有一个表示有线格式数据包的结构。在这种结构中是一系列其他结构。我有通用代码,在大多数情况下处理这个非常好,但这个结构数组的情况是抛出marshaller循环。
不安全的代码是不行的,因为我无法获得带有数组的结构的指针(argh!)。
我可以从this codeproject article看到,有一个非常好的,通用的方法,涉及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;
}
};
现在,如果只有结构 - &gt;字节数组/写入器版本我将被设置!提前谢谢!
答案 0 :(得分:2)
如果不控制结构的字节打包,则使用memcpy将字节数组复制到结构中是非常危险的。一次一个场地对一个结构进行编组和解组是更安全的。当然,您将失去您提供的示例代码的通用功能。
尽管回答你的真实问题(并考虑这个伪代码):
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;
}
};
答案 1 :(得分:1)
这可能不是正确的方法。允许CLR添加填充,重新排序项目并改变它存储在内存中的方式。
如果要执行此操作,请确保添加[System.Runtime.InteropServices.StructLayout]
属性以强制结构的特定内存布局。一般来说,我建议你不要乱用.NET类型的内存布局。
答案 2 :(得分:1)
实际上,可以使用不安全的代码来执行此操作。请参阅我从磁盘读取结构的帖子:Reading arrays from files in C# without extra copy.
答案 3 :(得分:0)
不改变结构肯定是合理的建议。我使用大量的StructLayout属性来指定打包,布局和字符编码。一切都很顺利。
我的问题只是我需要一个高性能且最好是通用的解决方案。性能,因为这是一个服务器应用程序和优雅的通用。如果你看一下codeproject链接,你会发现StructureToPtr和PtrToStructure方法的执行速度比简单的不安全指针的速度慢20倍。这是不安全代码充满胜利的领域之一。 C#只会让您拥有指向原语的指针(并且它不是通用的 - 无法获得指向通用的指针),这就是CLI的原因。
感谢psuedocode悲伤,我会看看它是否完成了工作并报告回来。
答案 4 :(得分:0)
我错过了什么吗?为什么不创建一个相同大小的新数组并在循环中单独初始化每个元素?
使用字节数据数组非常危险,除非您仅针对一个平台...例如,您的方法不考虑源数组和目标数组之间的不同字节顺序。
我对你的问题并不是很了解的一个原因是为什么在你的班级中将数组作为成员导致问题。如果该类来自.NET语言,则应该没有问题,否则,您应该能够将指针放在不安全的代码中并通过逐个指向的元素(使用不安全的代码)并添加来初始化新数组他们对它。