Выражение должно быть допустимо для изменения левосторонним значением

PVOID trampoline = (PVOID )1; //для примера присвоил рандомное значение
((PBYTE)trampoline)++; //тут ошибка (Выражение должно быть допустимо для изменения левосторонним значением)

Почему такая ошибка, ведь мы сначала преобразовали наш указатель к указателю на BYTE, после чего инкрементируем? Причем в чисто сишном компиляторе все нормально компилируется.


Ответы (1 шт):

Автор решения: AlexGlebe

стандарт :

7.6.3 Explicit type conversion (cast notation)

The result of the expression (T) cast-expression is of type T. The result is an lvalue if T is an lvalue reference type or an rvalue reference to function type and an xvalue if T is an rvalue reference to object type; otherwise the result is a prvalue. [Note 1 : If T is a non-class type that is cv-qualified, the cv-qualifier s are discarded when determining the type of the resulting prvalue; see 7.2. — end note]

перевод :

7.6.3 Явное преобразование типов (приведенная нотация)

Результат приведения выражения (T) имеет тип T. Результатом является значение lvalue, если T является типом ссылки lvalue или ссылкой rvalue на тип функции, и значение xvalue, если T является ссылкой rvalue на тип объекта; в противном случае результатом является значение prvalue. [Примечание 1 : Если T-тип, не относящийся к классу, который квалифицируется cv, квалификатор s cv отбрасывается при определении типа результирующего значения prvalue; см. 7.2. — конец примечания]

Приведение на объект даёт новый временный объект. Временный объект это не lvalue. А ссылка или (*ptr) будет lvalue после приведения типа. И её можно будет менять.

# include <cstdint>
# include <iostream>
typedef void * PVOID ;
typedef uint8_t * PBYTE ;
typedef uint8_t BYTE ;
BYTE arr[]={0,0,0};
PVOID trampoline = (PVOID )(&arr[0]);
int main(){
    // тут была ошибка (Выражение должно быть допустимо для изменения левосторонним значением)
    PBYTE && tmp = ((PBYTE)trampoline);
    tmp ++ ;
    std::cout<<"trampoline = "<<trampoline<<std::endl;
    std::cout<<"tmp = "<<(void*)tmp<<std::endl;
    (*(PBYTE*)&trampoline)++;
    std::cout<<"trampoline = "<<trampoline<<std::endl;
    ((PBYTE&)trampoline)++;
    std::cout<<"trampoline = "<<trampoline<<std::endl;
}

=>

trampoline = 0x404191
tmp = 0x404192
trampoline = 0x404192
trampoline = 0x404193

Справочник по Left-value Right-value :

variable = LValue
& variable = RValue
(* (any pointer)) = LValue
((T)(any value)) = RValue
(*(T*)(any pointer)) = LValue
((T&)(any link)) - LValue
→ Ссылка