#c #pointers #reference #memory-address
#c #указатели #ссылка #адрес памяти
Вопрос:
В C гарантированно ли совпадает адрес ссылки на разыменованный указатель с адресом указателя?
Или, написанное в коде, гарантировано ли, что следующее утверждение всегда будет верным?
SomeType *ptr = someAddress;
SomeType amp;ref = *ptr;
assert(amp;ref == ptr);
Комментарии:
1. @dlev: как он вообще мог «попробовать», гарантированно ли это будет то же самое? И зачем ему спрашивать, гарантировано ли это, если все, что он хочет знать, это является ли это равным для одного конкретного запуска одной конкретной программы в одной конкретной реализации C ?
2. @Steve он, очевидно, не может, но прогнать его пару раз должно быть более чем достаточно, чтобы убедить вас, что это правда. Тем не менее, вы правы, он действительно сказал » гарантировано «.
3. Код правильный, вопрос более «сомнительный». Я бы прочитал «адрес указателя» как
amp;ptr
, что не совпадает с адресом объекта, на который указывается.4. @dlev: исходя из этого, я убежден, что
sizeof(int) == sizeof(void*)
это гарантировано. Я предсказываю, что впереди будут неприятности ;-). Мы знаем только то, что попытка использовать Jesper’sassert
дает правильный ответ, потому что мы случайно знаем, что есть фундаментальная причина, по которой вы получите один и тот же ответ везде. Но если вы не знали, что он везде одинаков, то вы не могли полагаться на тест. И если бы вы знали, что везде одно и то же, вы бы уже знали ответ на вопрос…5. @Steve что может пойти не так? В любом случае, это всего лишь байты.
Ответ №1:
Да, это правильно и всегда будет правдой.
Ссылка — это не что иное, как псевдоним типа, на который она ссылается. У него нет отдельного существования, оно всегда связано с тем, к кому оно относится.
Ответ №2:
Да, при условии, конечно, что someAddress
это не нулевой указатель или иным образом не разрешено разыменовывать. В этом случае поведение не определено, хотя ваша реализация вполне может вести себя так, как будто они равны, особенно при низких уровнях оптимизации.
Если вы хотите быть точным, то amp;ref
на самом деле это не «адрес ссылки», а «адрес ссылочного элемента ссылки». Поскольку ref
был привязан к *ptr
, это означает, что referand of ref
и referand (или pointee, если вы предпочитаете) of ptr
являются одним и тем же объектом, и, следовательно, два адреса amp;ref
и ptr
равны.
И, как указывает Bo, то, с чем вы сравниваете amp;ref
, является «значением указателя» или «адресом, хранящимся в указателе», а не «адресом указателя».
Комментарии:
1. 1 важно заметить, что
amp;ref
возвращает не адрес, где хранится сама ссылка, а адрес объекта, на который делается ссылка.
Ответ №3:
Да, если у самой ссылки есть адрес, он управляется реализацией и недоступен из кода. В любом случае, это просто другое имя для того же объекта.
Ответ №4:
Да, ваше понимание верно. И для 99,9% кода в мире ваш код будет правильным. Для педантов в аудитории (и я среди них) это утверждение не всегда верно:
SomeType *ptr = someAddress;
SomeType amp;ref = *ptr;
assert(amp;ref == ptr);
Рассмотрим эту программу:
#include <cassert>
struct SomeType { void* operatoramp;() { return 0; } };
int main() {
SomeType *ptr = new SomeType;
SomeType amp;ref = *ptr;
assert(amp;ref == ptr);
}
Комментарии:
1. Будучи педантичным, я не мог не заметить, что 99.(9) просто равно 100.