Especificador NSLog / printf para NSInteger?

131

A NSIntegertiene 32 bits en plataformas de 32 bits y 64 bits en plataformas de 64 bits. ¿Hay un NSLogespecificador que siempre coincida con el tamaño de NSInteger?

Preparar

  • Xcode 3.2.5
  • Compilador llvm 1.6 (esto es importante; gcc no hace esto)
  • GCC_WARN_TYPECHECK_CALLS_TO_PRINTF encendido

Eso me está causando dolor aquí:

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {
    @autoreleasepool {
        NSInteger i = 0;
        NSLog(@"%d", i);
    }
    return 0;
}

Para el código de 32 bits, necesito el %despecificador. Pero si uso el %despecificador, recibo una advertencia al compilar para 64 bits sugiriendo que use %lden su lugar.

Si uso %ldpara que coincida con el tamaño de 64 bits, cuando compilo para el código de 32 bits recibo una advertencia que sugiere que use %den su lugar.

¿Cómo soluciono ambas advertencias a la vez? ¿Hay algún especificador que pueda usar que funcione?

Esto también impacta [NSString stringWithFormat:]y [[NSString alloc] initWithFormat:].

Steven Fisher
fuente

Respuestas:

296

Respuesta actualizada:

Puede utilizar los modificadores zy tpara manejar NSIntegery NSUIntegersin advertencias, en todas las arquitecturas.

Desea utilizar %zdpara firmado, %tupara no firmado y %txpara hexadecimal.

Esta información es cortesía de Greg Parker .


Respuesta original:

El enfoque oficial recomendado es usarlo %ldcomo su especificador y enviar el argumento real a a long.

Lily Ballard
fuente
66
Este es definitivamente el camino a seguir, pero creo que podría usar static inline NSIntToLong(NSInteger i) {return (long)i;}. Esto evita deshabilitar la comprobación de tipo por completo (es decir, si el tipo de i cambia).
Steven Fisher
3
Buen pensamiento por @ steven-fisher. Evite la advertencia con:static inline long NSIntToLong(NSInteger i) {return (long)i;}
Erik
3
También puede crear un NSNumber y registrarlo. NSLog(@"%@",@(mynsint)); stackoverflow.com/questions/20355439/…
orkoden
2
@KevinBallard Esto no debería ser un problema grave de rendimiento. De todos modos, no debe usar mucho NSLog en el código de producción. Si tiene que registrar muchas cosas por algún motivo, hágalo en un hilo separado.
Orkoden
44
A partir de Xcode 9.3 hay una advertencia al usar NSInteger como argumento de formato con %zd:Values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead
Rob MacEachern
2

La respuesta aceptada es absolutamente razonable, es conforme estándar y correcta. El único problema es que ya no funciona, lo cual es completamente culpa de Apple.

El formato% zd es el formato estándar C / C ++ para size_t y ssize_t. Al igual que NSInteger y NSUInteger, size_t y ssize_t son 32 bits en un sistema de 32 bits y 64 bits en un sistema de 64 bits. Y es por eso que la impresión de NSInteger y NSUInteger utilizando% zd funcionó.

Sin embargo, NSInteger y NSUInteger se definen como "largos" en un sistema de 64 bits y como "int" en un sistema de 32 bits (que es de 64 frente a 32 bits). Hoy, size_t se define en "largo" en todos los sistemas, que tiene el mismo tamaño que NSInteger (ya sea de 64 o 32 bits), pero de un tipo diferente. O las advertencias de Apple han cambiado (por lo que no permite pasar el tipo incorrecto a printf, aunque tenga el número correcto de bits), o los tipos subyacentes para size_t y ssize_t han cambiado. No sé cuál, pero% zd dejó de funcionar hace algún tiempo. Hoy no existe ningún formato que imprima NSInteger sin previo aviso en los sistemas de 32 y 64 bits.

Entonces, desafortunadamente, lo único que puede hacer es usar% ld y convertir sus valores de NSInteger a largo, o de NSUInteger a largo sin firmar.

Una vez que ya no construyes para 32 bits, puedes usar% ld, sin ningún tipo de conversión.

gnasher729
fuente
0

Los formateadores provienen de la función estándar printf de UNIX / POSIX. Use % lu para largos sin firmar ,% ld para largos,% lld para largos largos y % llu para largos sin firmar largos . Pruebe man printf en la consola, pero en Mac está incompleto. Las páginas de manual de Linux son más explícitas http://www.manpages.info/linux/sprintf.3.html

Ambas advertencias solo pueden ser reparadas por NSLog (@ "% lu", (sin signo largo) arg); combinado con un reparto, ya que el código se compilará en 32 y 64 bits para iOS. De lo contrario, cada compilación crea una advertencia por separado.

gato
fuente