Ваши предположения кажутся неверными. Во-первых, тип wchar_t
может иметь разную длину на разных машинах. У меня блок x64 Linux, это 4 байта - только это дает структуру размером get_pid
1032
байта. Возможно, вам будет интересно использовать вместо этого тип char16_t
или char32_t
(см., Например, здесь ).
Поскольку union
в Packet
перекрывает все поля, это также делает Packet
a 1040
структура размером в байт: 4
байтов для PacketHeader
, 1032
байтов для get_pid
- что на сегодняшний день является самой «длинной» структурой - и 4
байтов для заполнения. К сожалению, заполнение зависит от платформы c.
Чтобы избавиться от заполнения в компиляторе C / C ++, вам нужно будет использовать такие атрибуты, как G CC s __attribute__ ((packed))
или Visual C ++. #pragma pack(1)
(см., Например, this SO answer).
Однако будьте осторожны, смещения полей в C# также неверны: за исключением заголовка, все смещения полей в Packet
должно быть [FieldOffset(4)]
- так как в C ++ это union
, которое начинается с байта 4
(при нулевом заполнении).
Для переносимости также имейте в виду, что unsigned long long
является платформой, c также и что единственная гарантия для него - быть как минимум 64 бит. Если вам нужно ровно 64 бит, вы можете вместо этого использовать uint64_t
(см., Например, здесь ).
Вот код, который я использовал для определения размеров (Linux x64, G CC 9,3):
int main() {
std::cout << "packet_type: " << sizeof(packet_type) << std::endl;
std::cout << "copy_mem: " << sizeof(copy_mem) << std::endl;
std::cout << "get_base_addr: " << sizeof(get_base_addr) << std::endl;
std::cout << "get_pid: " << sizeof(get_pid) << std::endl;
std::cout << "completed: " << sizeof(completed) << std::endl;
std::cout << "PacketHeader: " << sizeof(PacketHeader) << std::endl;
std::cout << "Packet: " << sizeof(Packet) << std::endl;
std::cout << "wchar_t: " << sizeof(wchar_t) << std::endl;
return 0;
}
С заполнением (структуры по умолчанию):
packet_type: 4
copy_mem: 40
get_base_addr: 4
get_pid: 1032
completed: 8
PacketHeader: 4
Packet: 1040
wchar_t: 4
Нет заполнение (__attribute__ ((packed))
):
packet_type: 4
copy_mem: 28
get_base_addr: 4
get_pid: 1032
completed: 8
PacketHeader: 4
Packet: 1036
wchar_t: 4
Как было указано в комментариях, установка поля Packet
struct GetPid
на [FieldAlign(4)]
приведет к следующей ошибке времени выполнения:
Unhandled exception. System.TypeLoadException: Could not load type 'Packet' from assembly 'StructSize, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because it contains an object field at offset 4 that is incorrectly aligned or overlapped by a non-object field.
Один из способов обойти это - определите структуру get_pid
следующим образом:
[StructLayout(LayoutKind.Sequential, Pack = 0)]
public unsafe struct get_pid
{
public ulong len;
public fixed byte name[256];
}
Это все еще предполагает, что строка имени имеет длину 128
символов, каждый из которых является 2-байтовым Unicode. При этом свойство name
теперь имеет тип byte*
. Чтобы вернуть строку, должны работать следующие два метода:
public static unsafe string GetName(get_pid gp) =>
new string((sbyte*) gp.name, 0, 256, Encoding.Unicode);
public static unsafe string GetName(get_pid gp) =>
Marshal.PtrToStringUni(new IntPtr(gp.name), 256);