de1337ed
Estoy mirando mi libro de texto y estoy un poco confundido acerca del código que está ahí. En una parte, están realizando aritmética de punteros de la siguiente manera:
void* bp;
...
bp = (void*)((char*)(bp)+16);
...
pero luego, hacen lo siguiente:
void* bp;
...
bp = bp+16;
...
Siento que deberían ser dos cosas diferentes, pero lo están tratando como la misma cosa. Me siento así porque, por ejemplo, si tuviera que hacer un acceso a una matriz (para una matriz de enteros, por ejemplo), haría lo siguiente
int* a = malloc(n*sizeof(int));
...
q = *(a+1);
...
en este caso, ¿no estoy accediendo a los siguientes 4 bytes en la matriz de enteros y no al siguiente byte? Del mismo modo, siento que si tengo void* a, entonces *(a+1) deberían ser los siguientes 4 bytes… ¿O no es así? Gracias.
Es un desliz. aritmética en void *
no está definido por el estándar, pero algunos compiladores lo ofrecen como una extensión, comportándose igual que char *
para la aritmética. El segundo no es formalmente C válido, pero se deslizó presumiblemente por (mal) hábito.
-
Entonces, ¿la forma correcta de acceder a los siguientes 16 bytes sería primero convertir a char * y luego agregar 16? Lol, tengo que cambiar una buena cantidad de código ahora. Ah, y copié el primero un poco mal, hice un pequeño cambio pero no creo que haga una diferencia en mi pregunta.
– de1337ed
07/04/2012 a las 20:50
-
O podrías enviar a
uint64_t *
y agregue 2;) Sí, la forma portátil es convertir a un puntero a un tipo con tamaño conocido y hacer aritmética sobre eso. Si no necesita portabilidad y su compilador documenta esovoid *
la aritmética funciona de una manera específica, puedes usar eso. Pero claro, en algún momento tendrás que portar a un compilador diferente…–Daniel Fischer
7 abr 2012 a las 20:53
Antonin GAVREL
La respuesta aceptada es un buen resumen y quiero dejar más claro por qué usar uno u otro. 😉
Aunque (void *) y (char *) se pueden convertir de manera equivalente a cualquier otro tipo de puntero, solo es legal realizar aritmética de punteros en un (char *) y no con (void *) si desea cumplir con el estándar C.
¿Por qué ambos se usan como punteros? La mayoría de las conversiones de puntero hacia y desde (void *) se pueden realizar sin conversión, pero el uso de (char *) es una reminiscencia de los viejos tiempos.
GCC no advierte sobre la aritmética de punteros en (void *) ya que no es un compilador diseñado para cumplir con el estándar C sino para GNU C. Para cumplir con el estándar C, puede usar las siguientes banderas:
gcc -ansi -pedantic -Wall -Wextra -Werror <more args...>
Mi resultado final:
- Si quieres para realizar aritmética de punteros: use (char *)
- Si quieres para obtener la dirección del puntero para convertirlo en otro tipo más adelante: use (void *)
Ese segundo ejemplo no debería compilarse.
–Oliver Charlesworth
7 abr 2012 a las 20:48
@OliCharlesworth: no se compilará (o al menos activará una advertencia) si compila en modo conforme. gcc no se ajusta de forma predeterminada e implementa
void*
la aritmética como una extensión.–Keith Thompson
7 abr 2012 a las 20:54