Почти во всех реализациях два указателя равны тогда и только тогда, когда их представления равны, но стандарт этого не гарантирует.
Тот факт, что ptr1 == ptr2
не означает, что ptr1
и ptr2
имеют одинаковое представление. N1570 6.5.9 пункт 6:
Два указателя сравниваются равными, если и только если оба указателя равны нулю, оба
указатели на один и тот же объект (включая указатель на объект и
подобъект в начале) или функция, оба являются указателями на один
за последним элементом того же объекта массива, или один указатель на
один за концом одного объекта массива, а другой указатель на
начало другого объекта массива, который следует сразу за
первый объект массива в адресном пространстве.
Например, предположим, что указатель представлен в виде объекта из двух частей, причем первая часть идентифицирует сегмент памяти, а вторая часть - смещение байта в этом сегменте. Если два сегмента могут перекрываться, тогда могут быть два разных представления указателя для одного и того же адреса памяти. Два указателя будут сравниваться как равные (и сгенерированный код, вероятно, должен будет выполнить некоторую дополнительную работу, чтобы это произошло), но если преобразование в intptr_t
просто копирует представление, то (intptr_t)ptr1 != (intptr_t)ptr2
.
(Возможно также, что преобразование указателя в целое число может нормализовать представление.)
Эта возможность объясняет, почему ==
и !=
хорошо определены для указателей на разные объекты, но операторы отношений (<
, <=
, >
, >=
) не определены. Операторы равенства должны определить, указывают ли два указателя на одно и то же местоположение, но реляционным операторам разрешено сравнивать только смещения и игнорировать базовую часть (при условии, что каждый объект находится в одном сегменте). На практике почти все современные системы имеют монолитное адресное пространство, и операторы равенства и реляции работают согласованно, даже если стандарт не требует от них этого.