TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.37K subscribers
Post #1037 3.94K
​​Плотно упаковываем данные
#новичкам

Мы все про выравнивание, да про выравнивание. Куча средств языка, которые позволяют грамотно работать с требованиями к alignment'у данных.

А что если меня это все достало и я просто хочу понятной человеческой укладки данных? Подряд, без всяких паддингов непонятных. Можно так?

В С++ можно все. Ну почти.

Решение лежит за рамками стандарта. Оно и понятно, правила для выравнивания данных в нем очень гибкие, в основном все дается на откуп реализации. И инструменты для мануального управления выравниванием тоже находятся в руках конкретных компиляторов.

✅ #pragma pack. Это нестандартная директива препроцессора, которая тем не менее поддерживается большой тройкой компиляторов

В общем виде #pragma pack может использоваться тремя основными способами(будет немного нудно, но дождитесь примеров):

#pragma pack(push, n)
#pragma pack(pop)
#pragma pack(n)


- n - целое число, обычно степень двойки: 1, 2, 4, 8, 16 и т.д. Оно задаёт максимальное выравнивание для каждого члена. Член будет размещён по смещению, кратному min(n, alignof(тип)). Фактически n ограничивает выравнивание сверху.

- push - помещает текущее значение упаковки в стек (сохраняет его). Если после pushуказано n, то сначала сохраняется текущее, а затем устанавливается новое значение.

- pop - извлекает последнее сохранённое значение из стека и восстанавливает его.

На примерах это выглядит так:

struct Test {
char c; // смещение 0
int i; // смещение 4 (3 байта паддинга)
};

static_assert(sizeof(Test) == 8);
static_assert(alignof(Test) == 4);

#pragma pack(push, 1)
struct Packed {
char c; // смещение 0
int i; // смещение 1 (паддинга нет)
};
#pragma pack(pop)

static_assert(sizeof(Packed) == 5);
static_assert(alignof(Packed) == 1);

#pragma pack(push, 2)
struct Packed2 {
char c; // смещение 0
double d; // смещение 2 (1 байт паддинга после c)
};
#pragma pack(pop)

static_assert(sizeof(Packed2) == 10);
static_assert(alignof(Packed2) == 2);


Особенность механики работы со стеком в том, что мы можем применять одинаковое выравнивание для целого набора структур одной директивой.

✅ attribute((packed)). Этот атрибут поддерживается gcc и clang. Механика у него чуть попроще - полностью убирает паддинги и выставляет выравнивание 1 для самого типа:

struct attribute((packed)) PackedStruct {
char c;
int i;
short s;
};

static_assert(sizeof(PackedStruct) == 7);
static_assert(alignof(PackedStruct) == 1);


Удобно, если не нужно сложной логики.

✅ У нас же есть стандартный плюсовый синтаксис атрибутов. Давайте его и используем. В C++11 и новее также можно написать [[gnu::packed]] и эффект будет такой же, как в предыдущем пункте:

struct [[gnu::packed]] PackedStruct1 {
char c;
int i;
short s;
};

static_assert(sizeof(PackedStruct1) == 7);
static_assert(alignof(PackedStruct1) == 1);


Самая главная причина использовать плотную упаковку данных - это когда вам нужно в точности соответствовать компоновке данных в языке какому-либо требованию на уровне битов (аппаратура или протокол) и для этого требуется нарушить обычное выравнивание.

Большинство сетевых протоколов определяют строгую последовательность полей без лишних байтов. Использование упакованных структур позволяет им в точности соответствовать спецификации.

Но надо обязательно помнить про досуп к невыровненным данным: на некоторых архитектурах это в принципе приводит к ошибкам, а на других - к потенциальной деградации производительности(но это не точно, надо мерять).

Align yourself. Stay cool.

#cpp11 #compiler #NONSTANDARD
  • ❤ 24
  • 👍 9
  • 🔥 5
  • 😁 5
More from @grokaemcpp
  1. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  2. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  3. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  4. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
  5. Sep 28, 2026​​Stacktrace #опытным Одна из проблема исключений - непонятно, откуда оно прилетело. Ну да…
  6. Sep 25, 2026​​std::spanstream #опытным Радостная весть для всех, кто пользуется iostreams! В C++23 доб…
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 →