Це не визначена поведінка , незалежно від того, що хтось, чиновник чи інше , говорить, тому що це визначено стандартом. p->s
, за винятком випадків, коли використовується як значення, оцінює покажчик, ідентичний (char *)p + offsetof(struct T, s)
. Зокрема, це дійсний char
вказівник усередині об’єкта malloc'd, і за ним відразу 100 (або більше залежних від міркувань вирівнювання) послідовних адрес, які також є дійсними як char
об'єкти всередині виділеного об'єкта. Те, що вказівник було отримано, використовуючи ->
замість того, щоб явно додавати зміщення до покажчика, повернутого malloc
, переданим char *
, не має значення.
Технічно p->s[0]
- це єдиний елемент char
масиву всередині структури, наступні декілька елементів (наприклад, p->s[1]
наскрізь p->s[3]
) - це, ймовірно, байти підкладки всередині структури, які можуть бути пошкоджені, якщо ви виконувати присвоєння структурі в цілому, але не якщо ви просто отримаєте доступ до окремих члени та інші елементи - це додатковий простір у виділеному об’єкті, яким ви вільні користуватися, але вам подобається, якщо ви підкоряєтесь вимогам вирівнювання (і char
не має вимог вирівнювання).
Якщо ви стурбовані тим, що можливість перекриття із заповненням байт в структурах можете якої - то чином Invoke носових демонів, ви могли б уникнути цього, замінивши 1
в [1]
багатозначно , яке гарантує , що немає оббивки в кінці структури. Простий, але марнотратний спосіб зробити це - зробити структуру з однаковими членами, за винятком масиву в кінці, і використовувати s[sizeof struct that_other_struct];
для масиву. Тоді p->s[i]
чітко визначається як елемент масиву в структурі для i<sizeof struct that_other_struct
та як об'єкт char за адресою, що знаходиться в кінці структури для i>=sizeof struct that_other_struct
.
Редагувати: Насправді, у наведеному вище трюку для отримання потрібного розміру вам може знадобитися також поставити об'єднання, що містить кожен простий тип перед масивом, щоб переконатися, що масив починається з максимального вирівнювання, а не посередині прокладки інших елементів . Знову ж таки, я не вважаю, що щось із цього є необхідним, але я пропоную це для найбільш параноїдальних мовних юристів.
Редагування 2: Перекриття байтами з підкладкою, безумовно, не є проблемою через іншу частину стандарту. C вимагає, що якщо дві структури узгоджуються в початковій підпорядкованості своїх елементів, до загальних початкових елементів можна отримати доступ через вказівник на будь-який тип. Як наслідок, якщо було оголошено структуру, ідентичну, struct T
але з більшим кінцевим масивом, елемент s[0]
повинен був би збігатися з елементом s[0]
в struct T
, і наявність цих додаткових елементів не могла б вплинути або вплинути на доступ до загальних елементів більшої структури за допомогою вказівника на struct T
.