Подтвердить что ты не робот

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

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

struct person p;
struct person *pp;

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

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

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

Я прав?

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

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

Ответ 3

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

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

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

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

Ответ 4

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

Ответ 5

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

v.x, оператор-член, действителен только для структур. v->x, член оператора указателя, имеет значение только для указателей структуры.

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

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

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

К сожалению, я не знаю, какая из них (если таковая имеется) истинна.

Ответ 6

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

адрес (человек) + смещение (возраст)

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

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

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