struct inotify_event
объявлено так:
struct inotify_event {
int wd; /* Watch descriptor */
uint32_t mask; /* Mask describing event */
uint32_t cookie; /* Unique cookie associating related
events (for rename(2)) */
uint32_t len; /* Size of name field */
char name[]; /* Optional null-terminated name */
};
Проблема в элементе гибкого массива name
.Имя не имеет числа внутри фигурных скобок, это означает, что &((struct inotify_event*)0)->name[0] == offsetof(struct inotify_event, name)
, т.е.память для элементов внутри элемента name
начинается ВПРАВО ПОСЛЕ структуры.
Теперь, если мы хотим рассказать об одном событии inotify, нам понадобится дополнительное место для имени после структуры.Динамическое распределение может выглядеть следующим образом:
char name[] = "this is the name of this event";
struct inotify_event *obj = malloc(sizeof(*obj) * (strlen(name) + 1));
obj->wd = smth;
obj->mask = smth2;
obj->len = strlen(name) + 1;
// fun fact: obj->name = &obj[1] . So if you ware to place array of inotify_events, you would overwrite the second member here.
memcpy(obj->name, name, obj->len);
Память для элемента структуры name
идет сразу после struct inotify_event
и выделяется с тем же malloc.Поэтому, если мы хотим иметь массив inotify_events и скопировать их вместе с именем, следующая структура inotify_event может быть не выровнена.
Предположим, alignof(struct inotify_event) = 8
и sizeof(struct inotify_event) = 16
и char name[] = "A";
, так что strlen(name) = 1
(strlen
исключает подсчет завершающего нулевого байта) и то, что мы хотим сохранить массив inotfiy_events внутри буфера.Сначала мы копируем структуру - 16 байтов.Затем мы копируем имя - 2 байта (включая нулевой байт).Если бы мы скопировали следующую структуру, она была бы не выровнена, потому что мы скопировали бы ее, начиная с 18-го байта (sizeof(struct inotfy_event) + strlen(name) + 1
) в буфере, который не делится на alignof(struct inotify_event)
.Нам нужно вставить 5 байтов дополнительного дополнения, и мы должны сделать это вручную, после первого члена массива, чтобы следующий struct inotify_event
был скопирован в 24-й байт.
Однако нам также необходимо уведомитькод пользователя / приложения о том, сколько нужно увеличить указатель, чтобы перейти к следующему члену массива структуры.Таким образом, мы увеличиваем obj->len
на количество байтов заполнения.Так что obj->len
равно strlen(name) + 1 + number of padding bytes inserted to make the next array member aligned
или равно 0, в случае отсутствия имени.
Проверьте код примера на странице руководства.В цикле, где мы перебираем struct inotify_events, есть строка:
ptr += sizeof(struct inotify_event) + event->len
Ptr - это char*
указатель на текущий / следующий элемент массива.Нам нужно увеличить указатель не только на sizeof(struct inotify_event)
, но и на число strlen(name) + 1
байт + вставка отступа к следующему элементу массива.Таким образом, мы можем сохранить элемент массива выровненным в соответствии с его необходимым выравниванием.В следующей позиции находится следующий struct inotify_event
.
. Для получения дополнительной информации просмотрите арифметику указателей в C и гибкий член структуры массива.