c pointers 32bit-64bit void-pointers intptr

c - ¿Usar intptr_t en lugar de void*?



pointers 32bit-64bit (2)

¿Es una buena idea usar intptr_t como almacenamiento de propósito general (para contener punteros y valores enteros) en lugar de void* ? (Como se ve aquí: http://www.crystalspace3d.org/docs/online/manual/Api1_005f0-64_002dBit-Portability-Changes.html )

Por lo que ya he leído:

  • int -> void* -> int roundtrip no garantiza que tenga el valor original; Supongo que int -> intptr_t -> int hará
  • la aritmética de puntero en void* e intptr_t requiere moldes, por lo que ninguno obtiene ventaja aquí
  • void* significa intptr_t menos explícitas al almacenar punteros, intptr_t significa menos intptr_t cuando se almacenan valores enteros
  • intptr_t requiere C99

¿Qué más debería tomar en consideración?


¿Es una buena idea usar intptr_t como almacenamiento de propósito general (para contener punteros y valores enteros) en lugar de void* ?

No.

intptr_t no se garantiza que exista. Primero, como nota, fue introducido en C99. En segundo lugar, no se requiere que las implementaciones tengan un tipo de entero lo suficientemente grande como para contener los valores del puntero convertido sin pérdida de información.

Es poco probable que la conversión de un int a intptr_t y viceversa pierda información, pero no existe una garantía real de que intptr_t sea ​​más ancho que int .

Si desea almacenar valores de puntero, almacénelos en objetos de puntero. Para eso están los objetos del puntero.

Cualquier puntero a un objeto o tipo incompleto se puede convertir en void* y viceversa sin pérdida de información. No existe tal garantía para los punteros a las funciones, pero cualquier tipo de puntero a función se puede convertir a cualquier otro tipo de puntero a función y viceversa sin pérdida de información. (Me refiero al estándar C, creo que POSIX brinda algunas garantías adicionales).

Si desea almacenar un número entero o un valor de puntero en el mismo objeto, lo primero que debe hacer es volver a pensar su diseño. Si ya lo ha hecho y ha llegado a la conclusión de que realmente desea hacerlo, considere usar una unión (y lleve un registro detallado de qué tipo de valor ha almacenado más recientemente).

Hay API que usan un argumento void* para permitir que se pasen datos arbitrarios; ver, por ejemplo, la función POSIX pthread_create() . Se puede abusar de esto lanzando un valor entero a void* pero es más seguro pasar la dirección de un objeto entero.


No, no se puede garantizar que un tipo en particular sea una forma razonable de almacenar tanto punteros como enteros, y además, hace que el código sea confuso. Hay una mejor manera.

Si desea almacenar un entero y un puntero en el mismo objeto, el método limpio y portátil es usar una unión:

union foo { int integer_foo; void *pointer_foo; }

Esto es portátil y le permite almacenar todo tipo de cosas en el tamaño de almacenamiento necesario para el mayor de los dos. Se garantiza que siempre funciona.