Является ли (char *) NULL - (char *) NULL неопределенным поведением? - PullRequest
3 голосов
/ 24 января 2020

Является ли ((char *)NULL - (char *)NULL) UB?

ИМО ответ здесь не тривиален. Есть мысли?

Годболт ссылка для экспериментов https://godbolt.org/z/zgVGk9

PS

Я не спрашиваю о добавлении чего-либо нулевого указателя (как в предложенный обман), но только около один частный случай .

Ответы [ 2 ]

6 голосов
/ 24 января 2020

Выражение имеет неопределенное поведение.

(Этот вопрос был закрыт как дубликат этого вопроса , но в нем обсуждаются только указатель + целочисленная арифметика c, а не указатель- арифметика указателя c, о которой спрашивает этот вопрос. Не стесняйтесь закрыть вопрос как дубликат, если существует существующий вопрос, который конкретно задает вопрос о вычитании указателя-указателя.)

N1570 является проект стандарта ISO C 2011 года. Раздел 6.5.6, параграф 9, в котором обсуждается вычитание, гласит:

Когда вычитаются два указателя, оба должны указывать на элементы одного и того же объекта массива или один после последнего элемента объекта массива; В результате получается разница индексов двух элементов массива.

(Один объект, не являющийся массивом, рассматривается как элемент массива из 1 элемента, но здесь он неприменим. )

Указатель, полученный выражением (char*)NULL, не указывает ни на элемент объекта массива, ни на какой-либо другой объект (пункт 3 пункта 6.3.2.3), поэтому ((char *)NULL - (char *)NULL) нарушает . Нарушение должно вне ограничения или ограничения во время выполнения приводит к неопределенному поведению (параграф 2 раздела 4).

3 голосов
/ 24 января 2020

Короткий ответ - да, поведение не определено:

C17 J.2 Неопределенное поведение (информативное)

Поведение не определено в следующих обстоятельства:

  • Указатели, которые не указывают или не выходят за пределы одного и того же объекта массива, вычитаются (6.5.6).

Long (нормативный ) ответ таков:

C17 6.5.6 Аддитивные операторы

...

Когда вычтены два указателя, оба должны указывать к элементам одного и того же объекта массива или одному последнему элементу объекта массива; Результатом является разница индексов двух элементов массива. Размер результата определяется реализацией, а его тип (целочисленный тип со знаком) ptrdiff_t определен в заголовке <stddef.h>. Если результат не может быть представлен в объекте этого типа, поведение не определено. Другими словами, если выражения P и Q указывают соответственно на i -й и j -й элементы массива, выражение (P)-(Q) имеет значение i - j при условии значение вписывается в объект типа ptrdiff_t. Более того, если выражение P указывает либо на элемент объекта массива, либо на один элемент после последнего элемента объекта массива, а выражение Q указывает на последний элемент того же объекта массива, выражение ((Q)+1)-(P) имеет то же значение, что и ((Q)-(P))+1 и -((P)-((Q)+1)), и имеет значение ноль, если выражение P указывает на один последний элемент массива, хотя выражение (Q)+1 не указывает на элемент объект массива.

Поскольку (char *)NULL не указывает на массив, выражение (char *)NULL - (char *)NULL имеет неопределенное поведение, но, как вы тестировали на различных компиляторах, вы вполне можете получить значение 0 определяется во время компиляции. Стандарт C не гарантирует этого, но для создания чего-либо еще потребуется извращенный компилятор.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...