Маршаллер помогает выполнять преобразование между структурами .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++. В Визуальном С++:
#pragma pack(push, 1)
// ... struct declarations...
#pragma pack(pop)
Это означает, что все структуры, объявленные между двумя прагмами, будут иметь упаковку, равную единице. В ССЗ:
struct x {
// ...
} __attribute__((packed));
Это сделает то же самое. Вы можете #define __attribute__(x) на платформах Windows и #ifdef _WIN32 вокруг прагм, чтобы сделать код совместимым с обоими мирами.
person
OregonGhost
schedule
08.04.2011