¿Por qué no puedo hacer aritmética en un molde de un puntero vacío?

void foo(void *ptr, int numBytes) { (char*)ptr += numBytes; } 

Esto no se comstack en C. Conozco la alternativa. Pero ¿por qué esto no funciona? ¿Cuál es el problema?

El problema

El problema es que (char*)ptr no producirá un valor l , lo que significa que el valor no se puede modificar; se puede ver como un resultado temporal de la conversión, la conversión generará un valor de tipo char* .

Es semánticamente lo mismo que si tuviera el siguiente ejemplo, una conversión produce un valor temporal, a tal valor no se le puede asignar un nuevo valor.

 int x = 123; (float)x += 0.12f; /* (1), illegal */ /* ^-- sementically equivalent to `123.f += 0.12f` */ 

Solución

En su pregunta, ha declarado que ya conoce una solución alternativa a este problema, pero me gustaría escribir explícitamente la solución para mostrar cómo se puede modificar el valor de ptr incluso cuando los lanzamientos arrojan valores no modificables.

  1. Tome la dirección de su puntero para anular ,
  2. lanzar esta dirección a un puntero a apuntar a char ,
  3. desreferencia ese puntero, cediendo un puntero a char ,
  4. modifique este valor de rendimiento como si el void* original void* fuera del tipo char*

 *((char**)&ptr) += numbytes; // make `ptr` move forward `numbytes` 

( Nota : al eliminar la referencia de un puntero, se obtiene un lvalor ; de lo contrario, sería imposible cambiar el valor del apuntado al valor ubicado en una dirección almacenada en un puntero).

En el lado izquierdo de un = , necesitas un valor lvalue . Pero (char*)ptr no es un lvalue.

Eso es porque

(char*)ptr no es un lvalue.

Intenta esto en su lugar:

 void foo(void *ptr, int numBytes) { char* p = (char*)ptr; p += numBytes; } 

Actualizar

Puede encontrar una breve explicación de varios tipos de valores en cppreference.com . Esto habla de los tipos de valor en C ++ pero las ideas centrales se traducen a C.

A los efectos de esta discusión,

Un valor l es una expresión que identifica un objeto no temporal o una función no miembro.

Puede tomar la dirección de un lvalor y asignarla a un valor diferente.

Ejemplo:

 int i; int* p = &i; i = 20; 

A diferencia de,

Un prvalue (rvalue “puro”) es una expresión que identifica un objeto temporal (o un subobjeto del mismo) o es un valor no asociado con ningún objeto.

El literal 42 es un valor. Tú no puedes hacer:

 int* p = &42; 42 = 53; 

En esta línea,

  char* p = (char*)ptr; 

un valor de l ( p ) se crea a partir de (char*)ptr . Por lo tanto, es posible utilizar:

  p += numBytes;