Разъяснение относительно гибкого доступа к членам массива

Из C23 §6.7.2.1(20):

[...] когда оператор . (или ->) имеет левый операнд, который является (указателем) на структуру с гибким элементом массива, а правый операнд называет этот элемент, он ведет себя так, как если бы этот член был заменен самым длинным массив (с тем же типом элемента), который не делает структуру больше объекта, к которому осуществляется доступ; смещение массива должно оставаться смещением гибкого элемента массива, даже если оно будет отличаться от смещения заменяющего массива.

Я не уверен, что понимаю последнее предложение. Почему смещение замещающего массива отличается от смещения гибкого элемента массива (FAM)? Если заменяющий массив имеет тот же тип элемента, что и FAM, то не будет ли он иметь то же выравнивание, что и FAM, и, следовательно, то же самое смещение, что и FAM?

На вопрос: «Разве он не будет иметь такое же выравнивание, как FAM, и, следовательно, такое же смещение, как FAM?»: Это не требование стандарта C.

Eric Postpischil 17.08.2024 14:01

Спасибо @EricPostpischil, я думал, что это будет следовать из требования, чтобы замещающий массив имел тот же тип элемента, что и FAM. Я до сих пор не понимаю, почему это не так.

user51462 17.08.2024 14:16

Хотя мне ничего не известно, реализация C может решить сделать последний член структуры «выровненным по правому краю». Например, при четырехбайтовом выравнивании int и восьмибайтовом выравнивании double реализация C может составить struct { double d; int i[5]; } восемь байтов d, четыре байта заполнения, затем 20 байтов i, тогда как struct {double d; int i[6]; } будет восемь байтов d, без байтов заполнения, тогда 24 байта i. Оба они выравнивают свои элементы по мере необходимости и используют тот же объем пространства, что и традиционный макет (минимальное необходимое дополнение перед каждым элементом, а затем то, что необходимо в конце)…

Eric Postpischil 17.08.2024 14:39

… Итак, если они оба используют одно и то же пространство и удовлетворяют всем требованиям, зачем предпочитать традиционную планировку макету с выравниванием по правому краю? Другая гипотетическая возможность заключается в том, что реализация C может использовать другое выравнивание для больших членов структуры. Например, если член равен int i[1024];, то выровняйте его по строке кэша, а не только по четырем байтам, как это было бы сделано для int i[3];. Тогда для учета этого необходимо правило гибких смещений элементов массива.

Eric Postpischil 17.08.2024 14:42

@EricPostpischil: ваши аргументы звучат правильно, но правильное выравнивание члена гибкого массива выглядит странно ;-)

Serge Ballesta 17.08.2024 17:28

Спасибо @EricPostpischil, мне нравится пример с кешем.

user51462 20.08.2024 05:57
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
6
86
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Стандарт C не описывает подробно, как заполнение располагается в структуре. Единственное требование — отсутствие отступов в начале.

В частности, раздел 6.7.2.1p17 стандарта C23 гласит:

... Внутри объекта структуры могут быть безымянные отступы, но не в его начале

И 6.7.2.1p19 гласит:

В конце структуры или объединения может быть безымянное дополнение.

Например, учитывая следующие структуры:

struct foo1 {
    int i;
    double d;
    int f[3];
};

struct foo2 {
    int i;
    double d;
    int f[];
};

Компилятор мог бы расположить их следующим образом:

// total size: 32 bytes
struct foo1 {
    int i;                // offset 0
    // 4 bytes padding
    double d;             // offset 8
    // 4 bytes padding
    int f[3];             // offset 20
};

// total size: 16 bytes + flexible array member
struct foo2 {
    int i;                // offset 0
    // 4 bytes padding
    double d;             // offset 8
    int f[];              // offset 16
};

Тогда, если вы создали экземпляр struct foo2 с тремя гибкими членами массива следующим образом:

struct foo2 *x = malloc(sizeof(struct foo2) + 3 * sizeof(int));

«Масив замены» в этом случае будет иметь тип int[3], поскольку это максимально допустимый размер с учетом фактического выделенного объекта.

Смещение x->f должно быть равно 16 в соответствии с отрывком, который вы выделили жирным шрифтом, даже если экземпляр struct foo1, член f которого имеет тот же размер, что и массив замены выше, будет иметь этот элемент со смещением 20.

Спасибо @dbush, но почему смещение foo1.f должно иметь какое-либо отношение к смещению foo2.f? foo1 и foo2 — разные типы.

user51462 20.08.2024 05:39

Это разные типы, но компилятор мог бы обращаться с ними одинаково в отношении заполнения, если бы не указанное вами правило.

dbush 20.08.2024 13:49

Другие вопросы по теме