¿Por qué / cuándo usar `intptr_t` para el moldeado de texto en C?

Tengo una pregunta sobre el uso de intptr_t contra long int . He observado que el aumento de las direcciones de memoria (por ejemplo, a través de la aritmética del puntero manual) difiere según el tipo de datos. Por ejemplo, incrementar un puntero de char agrega 1 a la dirección de memoria, mientras que incrementar un puntero de int agrega 4, 8 para un doble, 16 para un doble largo, etc.

Al principio hice algo como esto:

 char myChar, *pChar; float myFloat, *pFloat; pChar = &myChar; pFloat = &myFloat; printf( "pChar: %d\n", ( int )pChar ); printf( "pFloat: %d\n", ( int )pFloat ); pChar++; pFloat++; printf( "and then after incrementing,:\n\n" ); printf( "pChar: %d\n", (int)pChar ); printf( "pFloat: %d\n", (int)pFloat ); 

que compiló y ejecutó muy bien, pero XCode me dio advertencias para mi typecasting: “Transmitir de puntero a entero de diferente tamaño”.

Después de buscar en Google y atravesar (¿es esta última una palabra?), Vi que algunas personas recomiendan usar intptr_t :

 #include  

 printf( "pChar: %ld\n", ( intptr_t )pChar ); printf( "pFloat: %ld\n", ( intptr_t )pFloat ); 

que de hecho resuelve los errores. Entonces, pensé, a partir de ahora, debería usar intptr_t para encasillar punteros … Pero luego, después de un poco de inquietud, descubrí que podía resolver el problema simplemente reemplazando int con long int :

 printf( "pChar: %ld\n", ( long int )pChar ); printf( "pFloat: %ld\n", ( long int )pFloat ); 

Entonces mi pregunta es, ¿por qué es útil intptr_t y cuándo debería usarse? Parece superfluo en este caso. Claramente, las direcciones de memoria para myChar y myFloat eran demasiado grandes para caber en una int … así que encasillarlas a long int s resolvió el problema.

¿Es que a veces las direcciones de memoria son demasiado grandes para long int también? Ahora que lo pienso, supongo que es posible si tienes> 4 GB de RAM, en cuyo caso las direcciones de memoria podrían exceder 2 ^ 32 – 1 (valor máximo para entradas largas sin firmar …) pero C se creó mucho antes de que fuera imaginable, ¿verdad? ¿O eran ellos proféticos?

¡Gracias!

Aquí está el problema: en algunas plataformas, int es el tamaño correcto, pero en otras, long es el tamaño correcto. ¿Cómo sabes cuál es el que debes usar? Tu no Uno podría tener razón, pero el estándar no garantiza cuál sería (si es que lo es). Por lo tanto, el estándar proporciona un tipo que se define como el tamaño correcto, independientemente de la plataforma en la que se encuentre. Donde antes tenías que escribir:

 #ifdef PLATFORM_A typedef long intptr; #else typedef int intptr; #endif 

Ahora solo escribe:

 #include  

Y cubre tantos casos más. Imagine que está especializando el fragmento de arriba para cada plataforma en la que se ejecuta su código.

intptr_t es una nueva invención, creada después de que se imaginaran direcciones de memoria de 64 bits e incluso de 128 bits.

Si alguna vez necesita convertir un puntero en un tipo entero, siempre use intptr_t . Hacer cualquier otra cosa causará problemas innecesarios a las personas que necesiten portar su código en el futuro.

Tomó mucho tiempo resolver todos los errores con esto en progtwigs como Mozilla / Firefox cuando la gente quería comstackrlo en Linux de 64 bits.

Primero, intptr_t es solo para punteros de datos (no funciones) y no se garantiza que exista.

Entonces, no, no debes usarlo para imprimir. El %p es para eso. Solo tienes que lanzar tu puntero a (void*) y listo.

Tampoco es bueno para aritmética / acceder a bytes individuales. Transmitir a (unsigned char*) lugar.

intptr_t es realmente para las raras ocasiones en que tiene que interpretar punteros como enteros (que realmente no son). No es eso si no debes.

Puede hacer su vida más fácil usando el especificador de conversión p :

 printf("%p\n", (void *)foo); 

Además, la forma portátil de imprimir una variable de tipo (u)intptr_t es usar las macros PRI*PTR de inttypes.h ; lo siguiente es equivalente a usar p en mi plataforma (32 bits):

 printf("%08" PRIxPTR "\n", (uintptr_t)(void *)foo); 

Los moldes a void * son necesarios para la portabilidad total, pero se pueden omitir en plataformas con representaciones de puntero uniformes.