C ++ CLI структура в байтовом массиве - PullRequest
3 голосов
/ 01 декабря 2008

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

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

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

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

Ответы [ 5 ]

2 голосов
/ 01 декабря 2008

Использование 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 голос
/ 14 февраля 2009

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

1 голос
/ 01 декабря 2008

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

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

0 голосов
/ 03 февраля 2009

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

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

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

0 голосов
/ 02 декабря 2008

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

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

Спасибо за скорбящий psuedocode, я посмотрю, выполнит ли он свою работу, и сообщу.

...