ios - saber - que es un sistema operativo de 32 bits
¿Alternativas al tipo de conversión al formatear NS(U) Entero en arquitecturas de 32 y 64 bits? (3)
Con la versión de 64 bits de iOS, no podemos usar %d
y %u
para formatear NSInteger
y NSUInteger
. Porque para 64 bit, estos son typedef''d a long
y unsigned long
lugar de int
y unsigned int
.
Entonces, Xcode lanzará advertencias si intenta formatear NSInteger con% d. Xcode es agradable para nosotros y ofrece un reemplazo para esos dos casos, que consiste en un especificador de formato con prefijo l y una conversión de tipo a largo. Entonces nuestro código básicamente se ve así:
NSLog(@"%ld", (long)i);
NSLog(@"%lu", (unsigned long)u);
Lo cual, si me preguntas, es un dolor en el ojo.
Hace un par de días, alguien en Twitter mencionó los especificadores de formato %zd
para formatear variables firmadas y %tu
para formatear variables sin firmar en plataformas de 32 y 64 bits.
NSLog(@"%zd", i);
NSLog(@"%tu", u);
Lo cual parece funcionar. Y que me gusta más que encasillar.
Pero honestamente no tengo idea de por qué funcionan. En este momento, ambos son básicamente valores mágicos para mí.
Hice un poco de investigación y descubrí que el prefijo z
significa que el siguiente especificador de formato tiene el mismo tamaño que size_t
. Pero no tengo absolutamente ninguna idea de lo que significa el prefijo t
. Entonces tengo dos preguntas:
¿Qué significa exactamente %zd
y %tu
?
¿Y es seguro usar %zd
y %tu
lugar de la sugerencia de Apple para encasillar a largo?
Conozco las preguntas similares y las guías de transición de 64 bits de Apple, que recomiendan el enfoque %lu (unsigned long)
. Estoy pidiendo una alternativa para escribir el casting.
De http://pubs.opengroup.org/onlinepubs/009695399/functions/printf.html :
- z
Especifica que un [...] siguiente especificador de conversión se aplica a unsize_t
o al argumento de tipo entero con signo correspondiente; - t
Especifica que un especificador de conversión [...] siguiente se aplica a unptrdiff_t
o al argumento de tipo sin signo correspondiente;
Y de http://en.wikipedia.org/wiki/Size_t#Size_and_pointer_difference_types :
-
size_t
se usa para representar el tamaño de cualquier objeto (incluidas las matrices) en la implementación particular. Se utiliza como el tipo de devolución del operadorsizeof
. -
ptrdiff_t
se usa para representar la diferencia entre punteros.
En las plataformas actuales OS X e iOS tenemos
typedef __SIZE_TYPE__ size_t;
typedef __PTRDIFF_TYPE__ ptrdiff_t;
donde __SIZE_TYPE__
y __PTRDIFF_TYPE__
están predefinidos por el compilador. Para 32 bits, el compilador define
#define __SIZE_TYPE__ long unsigned int
#define __PTRDIFF_TYPE__ int
y para 64 bits el compilador define
#define __SIZE_TYPE__ long unsigned int
#define __PTRDIFF_TYPE__ long int
(Esto puede haber cambiado entre versiones de Xcode. Motivado por el comentario de @ user102008, lo he comprobado con Xcode 6.2 y actualicé la respuesta).
Entonces ptrdiff_t
y NSInteger
son typedef''d al mismo tipo : int
en 32 bits y long
en 64 bits. Por lo tanto
NSLog(@"%td", i);
NSLog(@"%tu", u);
trabaje correctamente y compile sin advertencias en todas las plataformas iOS y OS X actuales.
size_t
y NSUInteger
tienen el mismo tamaño en todas las plataformas, pero no son del mismo tipo, por lo que
NSLog(@"%zu", u);
en realidad da una advertencia cuando se compila para 32 bits.
Pero esta relación no está fija en ningún estándar (hasta donde yo sé), por lo tanto, no lo consideraría seguro (en el mismo sentido que asumir que el long
tiene el mismo tamaño que un puntero no se considera seguro). Podría romperse en el futuro.
La única alternativa al tipo de conversión que conozco es la respuesta a " Tipos de Fundación al compilar para la arquitectura arm64 y 32-bit ", usando macros de preprocesador:
// In your prefix header or something
#if __LP64__
#define NSI "ld"
#define NSU "lu"
#else
#define NSI "d"
#define NSU "u"
#endif
NSLog(@"i=%"NSI, i);
NSLog(@"u=%"NSU, u);
Prefiero simplemente usar un NSNumber
en NSNumber
lugar:
NSInteger myInteger = 3;
NSLog(@"%@", @(myInteger));
Esto no funciona en todas las situaciones, pero he reemplazado la mayoría de mi NS (U) Entero con el formato anterior.
Según Building 32-bit Like 64-bit , otra solución es definir la macro NS_BUILD_32_LIKE_64
, y luego simplemente puede usar los especificadores %ld
y %lu
con NSInteger
y NSUInteger
sin conversión y sin advertencias.