Является ли разыменованный указатель допустимым lvalue?

Принимая определение:

int i  = 10;
int *p = &i;

Почему *p является допустимым lvalue здесь:

*p+=10; 

Не должен ли *p оценивать значение int, хранящегося в &i, т.е. 10 и, следовательно, генерировать ошибку «Не lvalue»?


person Community    schedule 23.01.2011    source источник
comment
Я не знаю, почему тебя минусуют. Я думаю, это хороший вопрос   -  person SiegeX    schedule 24.01.2011
comment
Я всегда считал *p синонимом i и никогда не путался.   -  person Kevin    schedule 24.01.2011
comment
*p оценивается как значение int, хранящегося в &i, при использовании в качестве rvalue. Но как lvalue это то же самое, что и lvalue i.   -  person aschepler    schedule 24.01.2011
comment
*p всегда означает содержимое местоположения, на которое указывает p. Разница между интерпретацией *p как lvalue и rvalue заключается в том, что когда *p появляется как lvalue, подразумевается, что цель состоит в том, чтобы сохранить место, на которое указывает p, а когда *p используется в качестве rvalue понимается, что цель состоит в том, чтобы получить содержимое области памяти, на которую указывает p.   -  person Bob Jarvis - Reinstate Monica    schedule 25.12.2017
comment
@Kevin - мое внутреннее мысленное прочтение *p является объектом указателя p. Возможно, немного многословно, но мысленно это переводит *p += 10 в объект указателя p, который увеличивается на 10.   -  person Bob Jarvis - Reinstate Monica    schedule 25.12.2017
comment
С философской точки зрения, если бы *p всегда было r-значением, в чем был бы смысл указателей? Они будут эффективно доступны только для чтения...   -  person Jens    schedule 25.12.2017


Ответы (5)


lvalue — это выражение, указывающее на область хранения, которой можно управлять.

*p — это такое выражение, которое относится к области хранения. Это отличается от 10+=10;, потому что 10 не относится к области хранения, как переменная.

person SiegeX    schedule 24.01.2011
comment
10 - это выражение. Это просто не lvalue. - person Antti Haapala; 25.12.2017

Я полагаю, вы запутались с определением p. p на самом деле является переменной типа указатель на int, и ее значение инициализируется по адресу i.

Тем не менее, *p также является допустимым lvalue — допустимым выражением для места хранения.

person Michael Foukarakis    schedule 24.01.2011

Проще говоря, указатели указывают на объект (в общем смысле, не относящийся к ООП), а не на содержимое этого объекта. Так что да, разыменованный указатель является допустимым lvalue.

В терминах очень низкого уровня. Указатель — это не что иное, как адрес памяти, разыменованный указатель — это память по этому адресу.

person wich    schedule 25.01.2011

Не следует ли *p оценивать значение int, хранящегося в &i, т.е. 10 и, следовательно, генерировать ошибку «Не lvalue»?

Простыми словами,

* означает "значение по адресу".

*p означает "значение по адресу, заданному значением p".

*p = 10; означает "установить 10 как значение по адресу, заданному значением p".

lvalue — это выражение, которое ссылается на объект, хранящийся где-то в памяти. *p также является выражением, которое относится к объекту, хранящемуся в местоположении p.

person Maxim    schedule 09.10.2013

C11 6.5.3.2p4:

Семантика

...

  1. Унарный оператор * обозначает косвенность. Если операнд указывает на функцию, результатом является указатель функции; если он указывает на объект, результатом будет lvalue, обозначающее объект. Если операнд имеет тип «указатель на тип», результат имеет тип «тип». Если указателю присвоено недопустимое значение, поведение унарного оператора * не определено.

т.е. с

int i  = 10;
int *p = &i;

результатом *p является lvalue, обозначающее объект i.

Поэтому *p += 10 работает, так как это lvalue.

Теперь, если бы lvalue использовалось в контексте, где необходим сам объект, оно было бы преобразовано в значение, хранящееся в указанном объекте. Это называется преобразованием lvalue, и результирующее значение, конечно же, больше не является lvalue (C11 6.3.2.1p2).

person Antti Haapala    schedule 25.12.2017