Моя проблема состоит в том, чтобы отправить структуру между программой в C к программе C#.
Я сделал структуру в C#:
public struct NetPoint {
public float lat; // 4 bytes
public float lon; // 4 bytes
public int alt; // 4 bytes
public long time; // 8 bytes
}
Общий размер структуры должен составить 20 байтов.
Когда я делаю a sizeof()
в C++ этой структуры,
System.Diagnostics.Debug.WriteLine(
"SizeOf(NetPoint) = " +
System.Runtime.InteropServices.Marshal.SizeOf(new NetPoint()));
шоу консоли отладки:
SizeOf (Сетевой узел) = 24
Но я ожидал иметь 20 байтов. Почему я вижу различие?
Фактически, технически структура должна быть не менее из 20 байтов. Если вы выделите больше при отправке, получатель просто не будет их использовать / копировать. Проблема всегда в недостаточной доступности.
Тем не менее, я вижу проблему. Хм. Я думаю, что проблема в последнем длинном ... который ИМХО выравнивается по восьми байтам, вставляя четыре пустых байта раньше. Я думаю, что есть потеря производительности из-за того, что восьмибайтовый элемент не выровнен по восьмибайтовой границе.
Прикрепите атрибуты StructLayout для определения смещения каждого элемента вручную. Тогда вы сможете привести все в соответствие.
Ссылка: Как управлять физическим расположением полей данных в .NET Framework 2.0
[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct NetPoint {
public float lat; // 4 bytes
public float lon; // 4 bytes
public int alt; // 4 bytes
public long time; // 8 bytes
}
Это, по крайней мере, должно выравнивать элементы по однобайтовой границе. Вы можете пойти дальше, указав точное начало каждого элемента, если это необходимо.
TomTom ответил на этот вопрос довольно хорошо, я думаю, но есть другая альтернатива, если вы попадаете в сложную ситуацию с структурой COM-взаимодействия. Каждое поле можно выровнять отдельно с помощью атрибутов FieldOffset.
[StructLayout(LayoutKind.Explicit)]
public struct COMPoint
{
[FieldOffset(0)] public int X;
[FieldOffset(4)] public int Y;
}
Попробуйте добавить атрибут [StructLayout(LayoutKind.Sequential, Pack = 1)] и посмотрите, что произойдет. Я подозреваю 8-байтовый паддинг, так что это будет 3x8 байт.
Как правило, процессорам нравится, когда переменные выравниваются в памяти по адресу, который кратен их размеру, поэтому четырехбайтовое целое число должно находиться по адресу памяти, кратному четырем, а восьмибайтовое long
- по адресу, кратному восьми.
Разработчики языка C# (и C++) знают это, и они вставляют в структуры вставки для обеспечения необходимого выравнивания. Таким образом, фактическое расположение вашей структуры выглядит следующим образом:
public struct NetPoint {
public float lat; // 4 bytes Offset 0
public float lon; // 4 bytes Offset 4
public int alt; // 4 bytes Offset 8
int to_preserve_alignment; // 4 bytes Offset 12
public long time; // 8 bytes Offset 16
}
Вы можете исправить это, сделав long первым значением, как правило, если вы всегда помещаете самые большие значения в начало структур, у вас не будет никаких прокладок для сохранения выравнивания членов.
Вы также можете исправить это, добавив
[StructLayout(LayoutKind.Sequential, Pack = 4)]
перед объявлением структуры, но это приведет к неправильному выравниванию long time
, что снижает производительность. На некоторых процессорах это сильно снижает производительность (например, ALPHA AXP будет сбоить при неправильно выровненных членах). На процессорах x86 снижение производительности незначительно, но есть опасность, что на будущих процессорах снижение производительности будет значительным, поэтому лучше разрабатывать структуры для правильного выравнивания (а не упаковывать их), если это возможно.