Неочевидная тема. Для многих, кто программировал только на высокоуровневых ЯП, сложно принять, что заботиться нужно даже о порядке полей в структурах
– Выравнивание.
– Что?
– Выравнивание!
– ?
– Ну это там где потраченные на ничто байты, порядок, любить его неестественно, полей... Выравнивание!
И всё же у нас "под капотом" всё те же байты. Поэтому посмотрим, как устроены эти самые структуры.
#include <stdio.h> #include <math.h> // Подключаем для memcpy (да, неочевидно, но именно в "строках"). // Как будто qsort должен был быть в stdlib.h... #include <string.h> // Ещё немного примеров структур и их определения. typedef struct Point2d Point2d; struct Point2d { int x; int y; }; typedef struct User { unsigned char age; unsigned int ip; char name[16]; } User; // Именно с этой структурой мы будем развлекаться. typedef struct Example { char symbol; short num1; short num2; // Смотрим содержимое с этим полем и без него int some_int; } Example; void print_hex(void *a, int size) { char *byte = (char *)a; for (int i = 0; i < size; ++i) { printf("%02hhx ", *(byte + i)); } printf("\n"); } int main() { char buf[100]; Point2d a = { .y = -1, .x = 1}; // Ожидаемо, 8 байт (по 4 за каждый int) printf("Point2d size: %lu\n", sizeof(a)); memcpy(buf, &a, 8); print_hex(buf, 8); User u = { .name = "Ivanov Ivan", .age = 21, .ip = 0x7f000001 }; // Упс printf("User size: %lu (21 expected)\n", sizeof(u)); memcpy(buf, &u, sizeof(u)); print_hex(buf, sizeof(u)); Example e1 = { 'a', 1, 2, -1 }; printf("Example size: %lu\n", sizeof(e1)); memcpy(buf, &e1, sizeof(e1)); print_hex(buf, sizeof(e1)); }
Получаем 24 вместо 21 байта (если sizeof(int) == 4). Если присмотреться к байтам:
15 00 00 00 // age
01 00 00 7f // ip
49 76 61 6e 6f 76 20 49 76 61 6e 00 00 00 00 00 // name
Результаты с 2 short:
61
00 // ?
01 00
02 00
00 00 // ?
ff ff ff ff
С 1 short:
61
00 // ?
01 00
ff ff ff ff
Можно заметить, что 1-байтовые поля не выравниваются, 2-байтовые — выравниваются на чётные позиции, 4-байтовые — на позиции кратные четырём. Понятнее "листинг" с примером 2-х short полей можно записать так:
00: 61
01: 00 // ?
02: 01 00
04: 02 00
06: 00 00 // ?
08: ff ff ff ff
– где числа до ":" – отступ в байтах от начала структуры. Именно по этому отступу и выравниваются поля структуры.
Самообучение: разобраться с выравниванием в структуре User.
TODO: Дописать объяснение с картинами причин выравнивания, какая оптимизация идёт. Да, я забил на это и в версии 0.02