Реальная вещь о “->” и “.”

Я всегда хотел знать то, что является реальной вещью различие того, как компилятор видит, указатель на структуру (в C предполагают), и сама структура.

struct person p;
struct person *pp;

pp->age, Я всегда предполагаю, что компилятор делает: "значение стр + смещение атрибута "возраст" в структуре".

Но с чем это делает person.p? Это было бы почти то же. Для меня "программист", p не является адресом памяти, как сама "структура", но конечно это не то, как соглашение о компиляторе с ним.

Мое предположение, это - больше синтаксической вещи, и компилятор всегда делает (&p)->age.

Я корректен?

16
задан FrustratedWithFormsDesigner 26 May 2010 в 19:12
поделиться

6 ответов

Обновлено (см. Комментарии):

Вы правильно поняли, но есть важное различие только для глобальных и статических переменных : когда компилятор видит p.age для глобальной или статической переменной, он может заменить ее во время компиляции точным адресом поля age в структуре.

Напротив, pp-> age должно быть скомпилировано как «значение pp + смещение поля age », поскольку значение pp может измениться во время выполнения.

5
ответ дан 30 November 2019 в 16:36
поделиться

Поскольку p является локальным (автоматически) переменная, она хранится в стеке. Поэтому компилятор обращается к нему с точки зрения смещения относительно указателя стека (SP) или указателя кадра (FP или BP в архитектурах, где он существует). Напротив, * p относится к адресу памяти, [обычно] выделенному в куче, поэтому регистры стека не используются.

1
ответ дан 30 November 2019 в 16:36
поделиться

В обоих случаях структура и ее члены адресуются по

address(person) + offset(age)

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

Короткий ответ: когда компилятор не оптимизирует, вы правы. Как только компилятор начинает оптимизировать, гарантируется только то, что определено стандартом c.

Edit: Удалено ошибочное местоположение в стеке/куче для "pp->", так как указатель на struct может находиться как в куче, так и в стеке.

0
ответ дан 30 November 2019 в 16:36
поделиться

Эти два оператора не эквивалентны даже с «точки зрения компилятора». Оператор p.age транслирует в адрес p + смещение age , а pp-> age переводит в адрес содержится в pp + смещение возраста .

Адрес из переменной и адрес , содержащиеся в (указатель) переменной, - очень разные вещи.

Скажем, смещение возраста равно 5. Если p - это структура, ее адрес может быть 100, поэтому p.age ссылается на адрес 105.

Но если ] pp - указатель на структуру, его адрес может быть 100, но значение, хранящееся по адресу 100, не является началом структуры person , это указатель. Таким образом, значение по адресу 100 (адрес , содержащийся в pp ) может быть, например, 250. В этом случае pp-> age ссылается на адрес 255, а не 105. .

3
ответ дан 30 November 2019 в 16:36
поделиться

p->q - это, по сути, синтаксический сахар для (*p).q, поскольку он разыменовывает указатель p, а затем переходит к соответствующему полю q внутри него. Это экономит ввод для очень распространенного случая (указатели на структуры).

По сути, -> делает два обращения (разыменование указателя, разыменование поля), в то время как . делает только одно (разыменование поля).

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

28
ответ дан 30 November 2019 в 16:36
поделиться

Это вопрос, который я всегда задавал себе.

v.x, оператор member, действителен только для структур. v->x, оператор member of pointer, действителен только для указателей struct.

Так зачем же иметь два разных оператора, если нужен только один? Например, только ; компилятор всегда знает тип v, поэтому он знает, что делать: v.x, если v - struct, (*v).x, если v - указатель struct.

У меня есть три теории:

  • временная недальновидность K&R (я бы хотел, чтобы эта теория была ложной)
  • облегчение работы компилятора (практическая теория, учитывая время зачатия C :)
  • удобство чтения (какую теорию я предпочитаю)

К сожалению, я не знаю, какая из них (если вообще какая-нибудь) верна.

1
ответ дан 30 November 2019 в 16:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: