Это не определено поведение, независимо от того, что кто-нибудь, чиновник или иначе, говорит, потому что это определено стандартом. p->s
, за исключением случаев, когда используется как значение lvalue, приравнивается к указателю, идентичному (char *)p + offsetof(struct T, s)
. В частности, это действительный указатель char
внутри объекта malloc'd, и есть 100 (или более, зависимых от согласований) последовательных адресов, непосредственно следующих за ним, которые также действительны как объекты char
внутри выделенного объекта. Тот факт, что указатель был получен с использованием ->
вместо явного добавления смещения к указателю, возвращаемому malloc
, отлитый от char *
, не имеет значения.
Технически p->s[0]
является единственным элементом char
массива внутри структуры, следующие несколько элементов (например, p->s[1]
через p->s[3]
), вероятно, обивка байтов внутри структуры, которые могут быть повреждены при выполнении задания на структуры в виде целое, но нет, если вы просто обращаетесь к отдельным членам, а остальные элементы - это дополнительное пространство в выделенном объекте, который вы можете использовать, как вам нравится, до тех пор, пока вы выполняете требования к выравниванию (и char
не имеет требований к выравниванию).
Если вы обеспокоены тем, что возможность перекрытия с заполняющими байтами в структурах могут какой-то образом ссылаться на носовых демонов, вы могли бы избежать этого, заменив 1
в [1]
со значением, которое гарантирует, что нет обивки в конце структура. Простым, но расточительным способом сделать это было бы создание структуры с идентичными членами, за исключением массива в конце, и использовать для массива s[sizeof struct that_other_struct];
. Затем четко определяется как элемент массива в структуре для i<sizeof struct that_other_struct
и как объект char по адресу после конца структуры для i>=sizeof struct that_other_struct
.
Edit: На самом деле, в приведенном выше трюк для получения нужного размера, вы можете также необходимо поместить союз, содержащий все простой тип до массива, чтобы убедиться, что сам массив начинается с максимального выравнивания, а не в середина какого-либо другого элемента. Опять же, я не считаю, что это необходимо, но я предлагаю его самому параноику юристов-языковедов.
Редактировать 2: Наложение с байтами заполнения не является проблемой, из-за другой части стандарта. C требует, чтобы, если две структуры согласуются в исходной подпоследовательности их элементов, к элементам общих начальных элементов можно получить доступ с помощью указателя на любой тип. Как следствие, если была объявлена структура, идентичная struct T
, но с более крупным финальным массивом, элемент s[0]
должен был бы совпадать с элементом s[0]
в struct T
, и наличие этих дополнительных элементов не могло бы повлиять или не повлиять на доступ к общим элементам большей структуры с использованием указателя на struct T
.
Как и в приведенном выше коде, который не будет работать во время компиляции? Посмотрите на свою линию 'malloc'. В частности, тип decl. – jer
Это кажется вполне понятным, разумным и, прежде всего, * ответственным * вопросом. Не видя причины закрытого голосования. – cHao
@jer: Я спрашиваю, действительно ли трюк UB, а не если он компилируется. жаль, что я забыл ключевое слово 'struct', исправлено. –