Маршаллер помогает конвертировать структуры .NET и необработанные байты.В этом ответе я опубликовал простое решение, которое сводится к Marshal.StructureToPtr
и Marshal.PtrToStructure
.В отличие от более продвинутых решений, предложенных Иоганном дю Туа, это, на мой взгляд, лучшее, что вы можете сделать, если все, что вы хотите сделать, это протолкнуть некоторые структуры через поток байтов.
Если вы сделаете этовы можете безопасно привести к структуре C ++, если длина верна, и ваша структура C ++ объявлена с той же упаковкой, что и структура C # (т. е. #pragma pack
в VC ++ или __attribute__((packed))
в GCC).
Обратите внимание, что это также работает со строками C фиксированной длины, но не будет заботиться о порядке следования больших значений.Я нашел простое решение - предоставить геттеры и сеттеры для последней проблемы, которые просто поменяют байты соответствующим образом (с BitConverter
).
Некоторая проработка упаковки: Возьмите следующую структуру:
struct MyStruct {
uint8_t a;
float b;
};
С объявлением C # с StructLayout, Pack = 1, эта структура будет иметь размер пять байтов.Структура C ++, однако, может иметь восемь байтов (или даже больше), в зависимости от упаковки компилятора по умолчанию, который может с радостью вставить некоторые байты заполнения для выравнивания значения с плавающей точкой на 32-битной границе (просто пример).Из-за этого вы должны применять одну и ту же упаковку к структуре C # и C ++.В Visual C ++:
#pragma pack(push, 1)
// ... struct declarations...
#pragma pack(pop)
Это означает, что все структуры, объявленные между двумя прагмами, будут иметь упаковку из одного.В GCC:
struct x {
// ...
} __attribute__((packed));
Это будет делать то же самое.Вы можете #define __attribute__(x)
на платформах Windows и #ifdef _WIN32
вокруг прагм, чтобы сделать код совместимым с обоими мирами.