2014-10-20 4 views
5

Я запутался, почему мой компилятор бросает ошибку в следующих условиях:C - выражение должно быть изменяемым именующее

void funcExample (void * p_Buf, uint16_t len) 
{ 
    uint16_t i; 

    for (i = 0; i < len; i++) { 
     otherFunc (((uint8_t *)p_Buf)++); //error = expression must be a modifiable lvalue 
    } 
} 

, но если я бросаю перед перейти к otherFunc, это нормально, потому что ни одна проблема не увеличивающиеся непрямый указатель:

void funcExample (void * p_Buf, uint16_t len) 
{ 
    uint16_t i; 
    uint8_t * p_Buf_8bit; 

    p_Buf_8bit = (uint8_t *) p_Buf; 

    for (i = 0; i < len; i++) { 
     otherFunc (p_Buf_8bit++); 
    } 
} 

Нельзя ли увеличить указатель на пустоту после литья? я что-то здесь не понимаю?

+0

не идентичны, но * очень * [** подобный вопрос здесь **] (http://stackoverflow.com/questions/24002044/почему-кан-я-не-делать-арифметический на-монолитный из-а-ничтожного-указателя). – WhozCraig

ответ

5

операторы Cast в C:

6.5.4. p5 Предшествующее выражение с помощью имени типа в скобках преобразует значение выражения в именованный тип. Эта конструкция называется литой. 104) Приведение, которое указывает , преобразование не влияет на тип или значение выражения.

104) Литой не дает значение lvalue. Таким образом, приведение к квалифицированным типу имеет тот же эффект, как и гипс на неквалифицированного версии типа

Но унарного ++ требует именующего выражения, как указано:

6.5.3.1 , p1 Операнд оператора приращения или уменьшения префикса должен иметь атомный, квалифицированный, или неквалифицированный реальный или указательный тип, и должен быть изменяемым значением lvalue.

Таким образом, вы можете сделать:

p_Buf = (uint8_t*)p_Buf + 1 ; 

Где p_Buf является Левым и (uint8_t*)p_Buf является Rvalue.


Позвольте мне отметить, что в вашем втором примере вы не отбрасывают (как вы сказали), но вы объявляете указатель uint8_t. Затем, когда вы используете ++, вы не выполняете какие-либо приведения (потому что он имеет правильный тип), и операция действительна.

+0

Вы преобразовываете указатель 'void' в' uint8_t' вместо указателя на него. – Seprum

+0

@Seprum Нет, я не знаю. Возможно, вы видели старое редактирование. обновите страницу. – 2501

+0

уже отредактирован. – Seprum

0

Результатом операции литья является rvalue, а не lvalue. ((uint8_t *)p_Buf)++ - это просто не законный код.

1

Приращение void указатель в C - плохая идея. Большинство компиляторов даже не позволяют его компилировать. Используйте вместо этого:

p_Buf = (uint8_t*)p_Buf + 1; 
1

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

Когда вы нанесли p_Buf на номер uint8_t*, вы создали rvalue в C.Простыми словами, rvalues ​​ представляют значения переходных процессов, которые могут быть переданы в функции, назначенные переменным и т. Д. Пост-инкремент возвращает исходное значение, а затем обновляет переменную или ячейку памяти, где значение хранилось, увеличивая ее. Поскольку они существуют только для продолжительности выражения, rvalues ​​ не могут быть обновлены, а пост-инкремент не может работать с ними. Таким образом, проблема с

otherFunc (((uint8_t *)p_Buf)++); //error = expression must be a modifiable lvalue 

является то, что ((uint8_t *)pBuf) это просто Rvalue выражения, без фактического места хранения. Фактически, литой означает, что вы используете только значение p_Buf и больше не используете переменную p_Buf.

С другой стороны, когда вы назначаете бросание переменный:

p_Buf_8bit = (uint8_t *) p_Buf; 

то переменная p_Buf_8bit является именующего, которые представляют местоположение переменного или память. Это может быть после увеличивается, что делает это отлично сформированную заявление в C:

otherFunc (p_Buf_8bit++); 
+0

Благодарим вас за дополнительное объяснение - это действительно помогает. проблема заключается в временном/временном характере приведения (rvalue vs lvalue). Спасибо. – jaypee