Пример кода:
struct name
{
int a, b;
};
int main()
{
&(((struct name *)NULL)->b);
}
Означает ли это поведение undefined? Мы могли бы обсудить, является ли это "разыменованием нулевым", однако C11 не определяет термин "разыменование".
6.5.3.2/4 ясно говорит, что использование *
по нулевому указателю вызывает поведение undefined; однако он не говорит то же самое для ->
, а также не определяет a -> b
как (*a).b
; он имеет отдельные определения для каждого оператора.
В семантике ->
в 6.5.2.3/4 говорится:
Постфиксное выражение, за которым следует оператор → , и идентификатор обозначает член структуры или объекта объединения. Значение - это имя именованного элемента объекта которое первое выражение указывает, и является значением l.
Однако NULL
не указывает на объект, поэтому второе предложение кажется underspecified.
Также может быть 6.5.3.2/1:
Ограничения:
Операнд унарного оператора
&
должен быть либо обозначением функции, либо результатом[]
или унарный оператор*
или lvalue, который обозначает объект, который не является битовым полем и является не объявляется с помощью спецификатора класса хранения регистра.
Однако я чувствую, что полужирный текст неисправен и должен читать значение lvalue, которое потенциально обозначает объект, согласно 6.3.2.1/1 (определение lvalue) - C99 испортил определение lvalue, поэтому C11 пришлось переписать его и, возможно, этот раздел был пропущен.
6.3.2.1/1 говорит:
Значение lvalue является выражением (с типом объекта, отличным от void), которое потенциально обозначает объект; если lvalue не обозначает объект при его оценке, поведение undefined
однако оператор &
выполняет свой операнд. (Он не получает доступ к сохраненному значению, но отличается).
Эта длинная цепочка рассуждений, по-видимому, предполагает, что код вызывает UB, но он довольно незначительный, и мне непонятно, что предполагали авторы стандарта. Если на самом деле они намеревались что-либо, а не оставляли его для обсуждения:)