Всегда ли (void *) ptr == ptr верно?

Я исключил этот вопрос из своего последнего вопроса, потому что подумал, что это скорее индивидуальный вопрос. Итак, я нашел отрывки для преобразования указателя в стандарте, из которых относятся к моему вопросу:

6.3.2.3

Указатели

1 Указатель на void может быть преобразован в указатель на любой тип объекта или из него. Указатель на любой тип объекта может быть преобразован в указатель на void и обратно; результат должен быть равен исходному указателю.

...

4 Преобразование нулевого указателя в другой тип указателя дает нулевой указатель этого типа. Любые два нулевых указателя должны сравниваться как равные.

Сейчас там только сказано, что

(originaltype*)((void*)ptr) == ptr

всегда будет правдой, но как насчет

(void*) ptr == ptr

Не указано явно, верно это или нет. Или я неправильно истолковал 1 абзац?


person Yastanub    schedule 09.06.2019    source источник
comment
Я подозреваю, что (void*) ptr == ptr то же самое, что и (void*) ptr == (void*) ptr, потому что второй операнд будет неявно преобразован в void* для проведения сравнения. Хотя не уверен на 100% ...   -  person Nikos C.    schedule 09.06.2019
comment
Я считаю, что сравнение должно быть верным , если ptr не является указателем на функцию, и в этом случае стандарт не гарантирует этого.   -  person Tom Karzes    schedule 09.06.2019
comment
Что ж, это явно либо правда, либо неопределенное поведение.   -  person M.M    schedule 09.06.2019


Ответы (2)


C 2018 6.5.9 обсуждает ==. Параграф 2 определяет ограничения, и (void *) ptr == ptr удовлетворяет ограничениям, потому что один из вариантов - «один операнд является указателем на тип объекта, а другой - указателем на квалифицированную или неквалифицированную версию void». Затем в параграфе 5 говорится: «… Если один операнд является указателем на тип объекта, а другой - указателем на квалифицированную или неквалифицированную версию void, первый преобразуется в тип второго».

Таким образом, в (void *) ptr == ptr правый операнд преобразуется в (void *), поэтому выражение эквивалентно (void *) ptr == (void *) ptr, и мы можем ожидать, что оно будет истинным.

Строго говоря, пункт 6.3.2.3 о преобразовании указателя говорит нам только о том, что результат преобразования (void *) ptr обратно в исходный тип будет равен ptr. Он ничего не сообщает нам о значении (void *) ptr, и поэтому, учитывая только этот пункт, возможно, что два разных экземпляра (void *) ptr дадут разные результаты, если они содержат достаточно информации для получения чего-то, что будет сравниваться с равным оригинал ptr при обратном преобразовании.

Вернемся к 6.5.9, параграф 6 говорит нам:

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

Теперь, конечно же, мы ожидаем, что (void *) ptr == (void *) ptr будет правдой, по крайней мере, время от времени. Как это возможно? (void *) ptr не является нулевым указателем (при условии, что ptr не был), и мы не ожидаем, что этот случай покрывается концом одного массива и началом другого случая. Таким образом, мы ожидаем, что когда (void *) ptr == (void *) ptr оценивается как истинное, это должно быть потому, что оно находится в случае «указатели на тот же объект» или «указатели на один за последним элементом того же случая объекта массива». Это кажется единственным разумным способом интерпретации стандарта. Если это так, то этот случай (какой бы из них ни применялся иногда) должен применяться постоянно, а «если и только если» говорит нам, что (void *) ptr == (void *) ptr всегда верно.

person Eric Postpischil    schedule 09.06.2019
comment
Обратите внимание, что это не относится к указателям на функции, поскольку они не считаются указывающими на объект. Я не знаю, беспокоился ли OP по поводу этого дела. - person Tom Karzes; 09.06.2019

* Если ptr является указателем на тип объекта, тогда (void *) ptr == ptr эквивалентно (void *) ptr == (void *) ptr. ptr справа неявно конвертируется в void *. (Если это указатель на квалифицированный тип const или volatile, эти квалификаторы теряются при неявном преобразовании.)

(void *) ptr, безусловно, равен самому себе, если только мы не развлекаемся праздным юмором, вроде того, что ptr является макросом, расширяющимся до выражения с побочными эффектами, которые меняют его значение при разных оценках, или является выражением с неопределенным значением, использование которого является неопределенным поведением.

Если ptr - указатель на функцию, то (void *) ptr == ptr требует диагностики; но ясно, что речь идет о типах объектов.

person Kaz    schedule 09.06.2019