TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.37K subscribers
Post #1043 4.09K
​​Как изучать выравнивание?
#новичкам

Небольшой дисклеймер для начала.

Надеюсь, что более менее все поняли, что в С++26 нет тредпула, mayby_unused, бесконечно расширяемого на стеке вектора и матриц. Ну а если нет, то у вас спина белая! Была вчера.

Back to the business.

Вы уже поняли, что вся эта тема паддингов и выравнивания вызывает самый широкий спектр эмоций от полного понимания и принятия до полного взрыва мозга. Хочется иметь какой-то механизм, который бы позволил для любой наперед заданной структуры посмотреть, как в точности в ней располагаются данные.

Такой механизм есть и он называется указатель на поле класса. У нас уже есть пост на эту тему, но кратко напомню. Это особый тип указателя, который хранит смещение поля относительно начала объекта в байтах.

struct Type {
int a;
int b;
float c;
};

&Type::a; // pointer to a
&Type::b; // pointer to b
&Type::c; // pointer to c


Кастанем этот указатель к числу и выведем его на консоль. Так мы сможем узнать с какого байта начинают лежать данные определенного поля класса.

template<typename T, typename FieldType>
void print_offset(FieldType T::*field) {
std::cout << std::dec << std::bit_cast<std::uintptr_t>(field) << "\n";
}

print_offset(&Type::a);
print_offset(&Type::b);
print_offset(&Type::c);
// OUTPUT
// 0
// 4
// 8


Первое поле очевидно начинается с нулевого смещения. Два других с шагом 4, так как все поля занимают по 4 байта и требования к выравниванию у них одинаковы.

Вспомним пару примеров из недавнего WAT

struct Empty {};

struct Good : Empty {
int a;
char b;
};

struct Bad {
int a;
char b;
};

template <typename T>
struct S : T {
char c;
};

print_offset(&S<Good>::a);
print_offset(&S<Good>::b);
print_offset(&S<Good>::c);
std::cout << std::endl;
print_offset(&S<Bad>::a);
print_offset(&S<Bad>::b);
print_offset(&S<Bad>::c);
// OUTPUT
// 0
// 4
// 5

// 0
// 4
// 8


Здесь четко видно, что данные поля c в классе S<Good> начинаются с пятого байта (из-за оптимизации хвостового заполнения), а в классе S<Bad> - с 8-го байта.

В общем, теперь гадать не нужно, можно просто проверить на любом примере и наглядно увидеть, как располагаются данные.

Don't guess. Stay cool.

#memory
  • ❤ 15
  • 👍 11
  • 🔥 5
  • ❤‍🔥 3
  • 😱 2
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 →