objective-c cocoa 64bit string-formatting llvm

objective c - ¿Por qué solo NSLog me advierte sobre el uso del especificador de formato de cadena% lu para NSUInteger?



objective-c cocoa (3)

Por alguna razón, recibo un error de compilación cuando intento hacer lo siguiente:

NSLog(@"row: %lu", indexPath.row);

donde row es de tipo NSUInteger . El error que recibo es

La conversión especifica el tipo ''unsigned long'' pero el argumento tiene el tipo ''NSUInteger'' (también conocido como ''unsigned int'')

Puedo hacer lo siguiente sin errores de compilación:

NSString * string = [NSString stringWithFormat:@"row: %lu", indexPath.row];

Estoy usando exactamente el mismo formato de cadena y el argumento de sustitución en ambos casos, pero ¿por qué NSLog freak out mientras que -stringWithFormat: parece estar perfectamente contento? Mi compilador es LLVM 1.6.


La documentación de Apple recomienda convertir el valor de 64 bits a un valor de 32 bits utilizando% lu y% ld. Esto plantea un problema si realmente utiliza los 32 bits adicionales. Las cadenas de formato% qu y% qd especifican un valor de 64 bits (sin signo y firmados respectivamente). Si desea código que compile en cualquiera de los modos, entonces los valores declarados como NSUInteger o NSInteger tendrán que convertirse en un UInt64 o SInt64 en la lista de parámetros para evitar la advertencia.


Me he encontrado con el mismo problema, y ​​aunque @Wevah es correcto y su respuesta funciona bien, hay otra opción que no requiere ningún cambio de código. Consulte la siguiente documentación de Apple para más detalles:

Guia de programacion de cuerdas | Dependencias de la plataforma

Guía de transición de 64 bits para el cacao | Construyendo 32 bits como 64 bits

La macro del preprocesador NS_BUILD_32_LIKE_64 es bastante útil. Puede configurarlo en la configuración de su proyecto Xcode (bajo GCC_PREPROCESSOR_DEFINITIONS ) o simplemente poner #define NS_BUILD_32_LIKE_64 1 en su archivo de encabezado precompilado (.pch). En mi aplicación, esto eliminó 11 advertencias sin ningún cambio de código.

Esto funciona porque unsigned int y unsigned long son del mismo tamaño (4 bytes) en iOS, por lo que cambiar el typedef de NSUInteger hace que el compilador (y el desarrollador) NSUInteger contentos, pero al hardware no le importa, ya que solo hace matemática de enteros ambos casos. :-)


Todos los dispositivos en los que iOS se ejecuta actualmente son de 32 bits. Si quieres silenciar la advertencia:

NSLog(@"row: %lu", (unsigned long)indexPath.row);

[Edición: a partir del iPhone 5s, ya no es cierto que iOS es siempre de 32 bits.]