Especificador NSLog / printf para o NSInteger?

131

A NSIntegeré de 32 bits em plataformas de 32 bits e 64 bits em plataformas de 64 bits. Existe um NSLogespecificador que sempre corresponde ao tamanho de NSInteger?

Configuração

  • Xcode 3.2.5
  • compilador llvm 1.6 (isso é importante; o gcc não faz isso)
  • GCC_WARN_TYPECHECK_CALLS_TO_PRINTF ligadas

Isso está me causando um pouco de tristeza aqui:

#import <Foundation/Foundation.h>

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

Para código de 32 bits, preciso do %despecificador. Mas se eu usar o %despecificador, recebo um aviso ao compilar para 64 bits, sugerindo que eu o use %ld.

Se eu usar %ldo tamanho de 64 bits, ao compilar o código de 32 bits, recebo um aviso sugerindo que o use %d.

Como faço para corrigir os dois avisos de uma só vez? Existe um especificador que eu possa usar que funcione também?

Isso também afeta [NSString stringWithFormat:]e [[NSString alloc] initWithFormat:].

Steven Fisher
fonte

Respostas:

296

Resposta atualizada:

Você pode usar os modificadores ze tpara manipular NSIntegere NSUIntegersem avisos, em todas as arquiteturas.

Você deseja usar %zdpara assinado, %tupara não assinado e %txpara hexadecimal.

Esta informação é cortesia de Greg Parker .


Resposta original:

A abordagem oficial recomendada é usar %ldcomo seu especificador e converter o argumento real em a long.

Lily Ballard
fonte
6
Este é definitivamente o caminho a percorrer, mas acho que posso usar static inline NSIntToLong(NSInteger i) {return (long)i;}. Isso evita desativar completamente a verificação de tipo (ou seja, se o tipo de i for alterado).
Steven Fisher
3
Bom pensamento por @ steven-fisher. Evite avisar com:static inline long NSIntToLong(NSInteger i) {return (long)i;}
Erik
3
Você também pode criar um NSNumber e registrá-lo. NSLog(@"%@",@(mynsint)); stackoverflow.com/questions/20355439/…
orkoden
2
@ KevinBallard Isso não deve ser um problema sério de desempenho. Você não deve usar muito NSLog no código de produção. Se você precisar registrar muitas coisas por algum motivo, faça-o em um thread separado.
orkoden
4
A partir do Xcode 9.3 há um aviso ao usar NSInteger como um argumento de formato com %zd:Values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead
Rob MacEachern
2

A resposta aceita é absolutamente razoável, está em conformidade com o padrão e está correta. O único problema é que ele não funciona mais, o que é completamente culpa da Apple.

O formato% zd é o formato padrão C / C ++ para size_t e ssize_t. Como o NSInteger e o NSUInteger, size_t e ssize_t são de 32 bits em um sistema de 32 bits e de 64 bits em um sistema de 64 bits. E é por isso que a impressão do NSInteger e do NSUInteger usando% zd funcionou.

No entanto, NSInteger e NSUInteger são definidos como "longos" em um sistema de 64 bits e como "int" em um sistema de 32 bits (que é de 64 vs 32 bits). Hoje, size_t é definido em "long" em todos os sistemas, que é do mesmo tamanho que o NSInteger (64 ou 32 bits), mas um tipo diferente. Os avisos da Apple foram alterados (portanto, não é permitido passar o tipo errado para printf, mesmo que tenha o número certo de bits) ou os tipos subjacentes para size_t e ssize_t foram alterados. Não sei qual, mas% zd parou de funcionar há algum tempo. Atualmente, não existe um formato que imprima o NSInteger sem aviso nos sistemas de 32 e 64 bits.

Portanto, a única coisa que você pode fazer infelizmente: Use% ld e converta seus valores de NSInteger para long, ou de NSUInteger para long assinatura.

Depois de não criar mais para 32 bits, você pode usar% ld, sem nenhuma conversão.

gnasher729
fonte
0

Os formatadores vêm da função de impressão padrão UNIX / POSIX. Use % lu por muito tempo não assinado ,% ld por muito tempo,% lld por muito tempo e % llu por muito tempo não assinado . Tente man printf no console, mas no Mac está incompleto. As páginas de manual do linux são mais explícitas http://www.manpages.info/linux/sprintf.3.html

Ambos os avisos podem ser corrigidos apenas pelo NSLog (@ "% lu", (long sem sinal) arg); combinado com um elenco, pois o código será compilado em 32 e 64 bits para iOS. Caso contrário, cada compilação cria um aviso separado.

gato
fonte