C++ CLI 结构到字节数组

发布于 2024-07-10 16:24:53 字数 885 浏览 10 评论 0原文

我有一个表示有线格式数据包的结构。 该结构中是其他结构的数组。 我有通用代码,在大多数情况下可以很好地处理这个问题,但是这个结构数组案例使编组器陷入循环。

不安全的代码是不行的,因为我无法获得指向带有数组的结构的指针(啊!)。

我可以从 这篇 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;
        }
    };

现在如果有结构 -> 字节数组/编写器版本我已经设置了! 提前致谢!

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 article that there is a very nice, generic approach involving C++/CLI that goes something like...

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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

她说她爱他 2024-07-17 16:24:53

如果您不控制结构的字节打包,则使用 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;
        }
    };

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.

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;
        }
    };
疾风者 2024-07-17 16:24:53

这可能不是正确的方法。 CLR 可以添加填充、重新排序项目以及更改其在内存中的存储方式。

如果您想执行此操作,请务必添加 [System.Runtime.InteropServices.StructLayout] 属性以强制该结构采用特定的内存布局。 一般来说,我建议您不要弄乱 .NET 类型的内存布局。

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.

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.

万劫不复 2024-07-17 16:24:53

实际上,可以编写不安全的代码来执行此操作。 请参阅我关于从磁盘读取结构的帖子: 从 C# 中的文件读取数组,无需额外副本。

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.

从﹋此江山别 2024-07-17 16:24:53

不改变结构当然是合理的建议。 我使用大量的 StructLayout 属性来指定包装、布局和字符编码。 一切都进展顺利。

我的问题是我需要一个高性能且最好是通用的解决方案。 性能,因为这是一个服务器应用程序并且通用的优雅。 如果您查看 codeproject 链接,您会发现 StructureToPtr 和 PtrToStructure 方法的执行速度比简单的不安全指针转换慢 20 倍左右。 这是不安全代码充满胜利的领域之一。 C# 只允许您拥有指向原语的指针(而且它不是通用的 - 无法获取指向通用的指针),所以这就是 CLI 的原因。

感谢您的伪代码悲伤,我将看看它是否完成工作并报告回来。

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.

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.

Thanks for the psuedocode grieve, I'll see if it gets the job done and report back.

北方的韩爷 2024-07-17 16:24:53

我错过了什么吗? 为什么不创建一个相同大小的新数组并在循环中单独初始化每个元素?

使用字节数据数组是非常危险的,除非您仅针对一个平台...例如您的方法不考虑源数组和目标数组之间的不同字节序。

我也不太明白你的问题是为什么在你的类中使用数组作为成员会导致问题。 如果该类来自 .NET 语言,则应该没有问题,否则,您应该能够在不安全代码中获取指针,并通过逐一遍历指向的元素(使用不安全代码)并添加来初始化新数组他们对它。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文