Структура C++ CLI в байтовый массив

У меня есть структура, представляющая пакет формата провода. В этой структуре есть множество других структур. У меня есть общий код, который очень хорошо справляется с этим для большинства случаев, но этот случай массива структур бросает маршаллер для цикла.

Небезопасный код не годится, так как я не могу получить указатель на структуру с массивом (ах!).

Из эта статья проекта я вижу, что существует очень хороший общий подход с использованием 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;
        }
    };

Теперь, если бы у меня была только структура -> байтовый массив / версия писателя, я бы установил! Заранее спасибо!

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
0
14 012
5

Ответы 5

Использование 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;
        }
    };

Вероятно, это неправильный путь. CLR позволяет добавлять отступы, изменять порядок элементов и изменять способ их хранения в памяти.

Если вы хотите сделать это, не забудьте добавить атрибут [System.Runtime.InteropServices.StructLayout], чтобы задать конкретный макет памяти для структуры. В общем, предлагаю не связываться с разметкой памяти .NET-типов.

Не изменять структуру, безусловно, является разумным советом. Я использую большое количество атрибутов StructLayout для указания упаковки, макета и кодировки символов. Все течет нормально.

Моя проблема в том, что мне нужно эффективное и, желательно, общее решение. Производительность, потому что это серверное приложение, универсальное для элегантности. Если вы посмотрите ссылку codeproject, вы увидите, что методы StructureToPtr и PtrToStructure работают примерно в 20 раз медленнее, чем простое небезопасное приведение указателя. Это одна из тех областей, где небезопасный код всегда приносит пользу. C# позволит вам иметь указатели только на примитивы (и он не является универсальным - не может получить указатель на универсальный), поэтому CLI.

Спасибо за горечь псевдокода, посмотрю, выполнит ли он свою работу, и доложу.

Я что-то упускаю? Почему бы не создать новый массив того же размера и инициализировать каждый элемент отдельно в цикле?

Использование массива байтовых данных довольно опасно, если вы не нацеливаетесь только на одну платформу ... например, ваш метод не учитывает различие в порядке байтов между исходным и целевым массивами.

Что-то, что я действительно не понимаю в вашем вопросе, - это то, почему наличие массива в качестве члена в вашем классе вызывает проблему. Если класс исходит из языка .NET, у вас не должно возникнуть проблем, в противном случае вы сможете взять указатель в небезопасном коде и инициализировать новый массив, пройдя по элементам, указанным на них, один за другим (с небезопасным кодом) и добавив их к этому.

На самом деле, для этого можно создать небезопасный код. См. Мой пост о чтении структур с диска: Чтение массивов из файлов на C# без лишнего копирования.

Другие вопросы по теме