TGViewer
Unity: Всё, что вы не знали о разработке Unity: Всё, что вы не знали о разработке @unsafecsharp · 1.74K subscribers
Post #231 2.57K
StructLayout

На самом деле довольно интересный аттрибут.
Давайте рассмотрим пример:


struct MyStruct {
public int a;
public byte b;
public int c;
public byte d;
}


Размер такой структуры определяется следующим образом:

public int a; // 4 байта
public byte b; // 1 байт
public int c; // 4 байта
public byte d; // 1 байт


Складываем, получаем 4 + 1 + 4 + 1 = 10 байт
Казалось бы, что тут сложного. Не все так просто 😉
Существует такое понятие как Pack size, то есть каким образом будет выровнена в памяти, если простым языком - каждая переменная будет минимум занимать размер pack size, максимум - кратное значение этому размеру:


public byte b; // 4 байта при Pack = 4
public byte b; // 1 байт при Pack = 1


Таким образом размер структуры будет вычисляться так:


public int a; // 4 байта
public byte b; // 4 байта
public int c; // 4 байта
public byte d; // 4 байта


Итого: 16 байт вместо 10 байт

Но мы умные и давайте переставим поля таким образом:


public int a; // 4 байта
public int c; // 4 байта
public byte b; // 1 байт
public byte d; // 1 байт


Получается, что теперь будет 10? А вот и снова нет 🙂
Теперь будет 12 байт. Почему так произошло?
Потому что последние два байта будут выровнены до 4х.

Что вообще такое Pack size и где он задается, о котором шла речь?
Это параметр аттрибута StructLayout:

[StructLayout(LayoutKind.Sequential, Pack = 4)]
struct MyStruct {
public int a;
public byte b;
public int c;
public byte d;
}


Мы можем задать Pack = 1, чтобы запаковать структуру по одному байту, таким образом мы получим 10 байт.

Что не так с паковкой по одному байту и почему не паковать все структуры таким образом по-умолчанию?
Ну, во-первых, это нарушает выравнивание в памяти. Например, если вы захотите после такого сделать Interlocked.Add(ref s.c), то получите краш, т.к. аддрес в памяти у поля c будет не кратным 4, а это приведет к крашу.
Во-вторых, я не знаю аллокатора, который не применяет общее выравнивание аллоцируемых объектов, т.е. в памяти он вероятнее всего будет занимать 12 байт, а не 10.

Что еще есть у StructLayout?

Еще есть Size, которым мы можем ограничить размер структуры до минимально необходимого:

[StructLayout(LayoutKind.Sequential, Size = 10)]
struct MyStruct {
public int a;
public int c;
public byte b;
public byte d;
}


Заметьте, что я специально переставил поля, т.к. если этого не сделать, то будет интересный эффект:
Размер sizeof(MyStruct) вернет нам 13 (т.к. Pack = 4, последний байт будет обрезан), а вот Marshal.SizeOf(s) вернет нам 10, т.к. он берет тип объекта и возвращает сколько нам необходимо было байт, чтобы создать этот инстанс, ведь Marshal.SizeOf принимает именно фактический инстанс объекта.
В любом случае, такого нужно не допускать.

Что про LayoutKind?

Для структур это значение может принимать 2 варианта:
LayoutKind.Sequential - как поля объявлены, так и раскладываем в памяти.
LayoutKind.Explicit - ручное распределение, необходимо указать FieldOffset аттрибут для каждого поля.

С Explicit можно "наслаивать" поля друг на друга, как самый простой вариант:

[StructLayout(LayoutKind.Explicit)]
struct MyStruct {
[FieldOffset(0)]
public int a;
[FieldOffset(4)]
public int c;
[FieldOffset(0)]
public long b;
}


Т.е. положили значения a и c, забрали одно значение b, которое будет содержать 2 int.

#unsafe #structlayout #sizeof
  • 🔥 43
  • 👍 23
  • 🤡 2
  • 🍓 2
  • ❤ 1
  • 🥰 1
More from @unsafecsharp
  1. Mar 2, 2026Век живи - век учись Я вот только сегодня узнал, что оказывается можно писать не только та…
  2. Feb 10, 2026Overlay У юнити, начиная с 2022.2, появилась возможность рисовать свои окна в SceneView, п…
  3. Dec 20, 2025Удобное API Вы наверняка сталкивались с такой проблемой: void Method<T>(System.Action<T> c…
  4. Dec 7, 2025Простые лайфхаки Часто встречаю в разных проектах подобные конструкции (на самом деле обыч…
  5. Nov 18, 2025Довольно интересная задачка попалась на собеседовании в гугле: Есть матрица (массив массив…
  6. Oct 12, 2025Unity.Profiling.IgnoredByDeepProfilerAttribute Аттрибут, который спасет вам время, если у…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →