Есть в C# такой хитрый атрибут как StructLayoutAttribute, с помощью него можно задавать расположение членов класса(структуры) как мы хотим. Имеет два конструктора:
StructLayoutAttribute(short) StructLayoutAttribute(LayoutKind)
Рассмотрим второй конструктор LayoutKind - задаёт расположение членов класса.
public enum LayoutKind
Члены этого перечисления:
Рассмотрим два последние значения. У нас есть следующая структура:
public struct Test { int i; byte j; }
Как вы думаете какой размер будет у неё 5 байт? Вовсе нет, по умолчанию выравнивание у нас идёт по 8. Просто сделаем:
Test s = new Test(); unsafe { Console.WriteLine("size is {0}", sizeof(Test)); }
Здесь мы получим результат 8, но мы можем сделать следующее:
[StructLayout(LayoutKind.Sequential, Pack = 1)] public struct Test { int i; byte j; }
Член Pack отвечает за выравнивание, по умолчанию он равен 8, поэтому мы изменим его значение на 1 и получим структуру которая будет выровнена на границе 1 байта. После чего её размер будет равен уже 5 байтам. С помощью Explicit как я уже говорил можно точно указать расположение членов класса. Пример.
[StructLayout(LayoutKind.Explicit, Pack = 1)] public struct Test2 { [FieldOffset(0)] public int i; [FieldOffset(3)] public byte j; }
Теперь уже размер структуры будет равен 4. Но если мы присвоим значение 3 j, то i не будет равно 3. Мы получим число 50331648. Всё это потому что у нас байты хранятся наоборот если помните( типа L(младший байт)H(старший байт). В шестнадцатеричной системе 50331648 будет равно 0x3000000. Не забывайте об этом.