До публикации C89 существовало несколько реализаций, которые пытались идентифицировать и перехватить доступ к массиву за пределами границ. Учитывая что-то вроде:
struct foo {int a[4],b[4];} *p;
такие реализации будут кричать при попытке доступа к p->a[i]
, если i
не находится в диапазоне от 0 до 3. Для программ, которым не нужно индексировать адрес типа массива lvalue p->a
для доступа что-нибудь за пределами этого массива, было бы полезно захватывать такие выходы за пределы допустимого.
Авторы C89 также почти наверняка знали, что программы часто использовали адрес массива фиктивного размера в конце структуры в качестве средства доступа к хранилищу вне структуры. Использование таких методов позволило делать вещи, которые иначе не могли бы быть выполнены так же хорошо, и, как утверждают авторы Стандарта, часть Духа С гласит: «Не мешайте программисту делать то, что нужно». сделано».
Следовательно, авторы Стандарта рассматривали такие обращения как нечто, что реализации могли бы поддерживать или нет на досуге, предположительно, исходя из того, что было бы наиболее полезным для их клиентов. Хотя часто для реализаций, которые обычно ограничивают доступ к структурам в массиве, было бы полезно предоставить возможность пропустить такие проверки в случаях, когда последним элементом структуры с косвенным доступом является массив с одним элементом (или, если они расширят язык, чтобы отменить ограничение времени компиляции (нулевые элементы), люди, пишущие такие реализации, предположительно будут способны распознавать такие вещи без необходимости объяснения их авторами Стандарта. Представление о том, что «неопределенное поведение» было задумано как какая-то форма запрета, похоже, на самом деле не утвердилось до публикации преемника C89.
Что касается вашего примера, то наличие указателя внутри структурной точки для последующего хранения в том же распределении должно работать, но с несколькими оговорками:
Если выделение передано realloc
, указатель внутри него станет недействительным.
Единственное реальное преимущество использования указателя по сравнению с гибким элементом массива состоит в том, что он позволяет указывать его где-то еще. Это может быть хорошо, если единственным видом «чего-то другого» всегда будет постоянный объект статической длительности, который никогда не должен быть освобожден, или, возможно, если это какой-то другой тип объекта, который не нужно освобождать, но может быть проблематичным, если он может содержать единственную ссылку на что-то, хранящееся в отдельном выделении.
Гибкие члены массива были доступны как расширение в некоторых компиляторах до написания C89 и были официально добавлены в C99. Любой достойный компилятор должен их поддерживать.