Spécificateur NSLog / printf pour NSInteger?

131

A NSIntegerest 32 bits sur les plates-formes 32 bits et 64 bits sur les plates-formes 64 bits. Existe-t-il un NSLogspécificateur qui correspond toujours à la taille de NSInteger?

Installer

  • Xcode 3.2.5
  • compilateur llvm 1.6 (c'est important; gcc ne le fait pas)
  • GCC_WARN_TYPECHECK_CALLS_TO_PRINTF allumé

Cela me cause du chagrin ici:

#import <Foundation/Foundation.h>

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

Pour le code 32 bits, j'ai besoin du %dspécificateur. Mais si j'utilise le %dspécificateur, j'obtiens un avertissement lors de la compilation pour 64 bits suggérant que j'utilise à la %ldplace.

Si j'utilise %ldpour correspondre à la taille 64 bits, lors de la compilation pour le code 32 bits, je reçois un avertissement suggérant que j'utilise à la %dplace.

Comment corriger les deux avertissements à la fois? Y a-t-il un spécificateur que je peux utiliser qui fonctionne sur l'un ou l'autre?

Cela a également un impact sur [NSString stringWithFormat:]et [[NSString alloc] initWithFormat:].

Steven Fisher
la source

Réponses:

296

Réponse mise à jour:

Vous pouvez utiliser les modificateurs zet tpour gérer NSIntegeret NSUIntegersans avertissement, sur toutes les architectures.

Vous souhaitez utiliser %zdpour signé, %tupour non signé et %txpour hexadécimal.

Cette information est une gracieuseté de Greg Parker .


Réponse originale:

L' approche officielle recommandée consiste à utiliser %ldcomme spécificateur et à convertir l'argument réel en un long.

Lily Ballard
la source
6
C'est certainement la voie à suivre, mais je pense que je pourrais l'utiliser static inline NSIntToLong(NSInteger i) {return (long)i;}. Cela évite de désactiver complètement la vérification de type (c'est-à-dire si le type de i change).
Steven Fisher
3
Bonne réflexion de @ steven-fisher. Évitez les avertissements avec:static inline long NSIntToLong(NSInteger i) {return (long)i;}
Erik
3
Vous pouvez également créer un NSNumber et le consigner. NSLog(@"%@",@(mynsint)); stackoverflow.com/questions/20355439/…
orkoden
2
@KevinBallard Cela ne devrait pas être un problème de performances sérieux. Vous ne devez de toute façon pas utiliser beaucoup de NSLog dans le code de production. Si vous devez enregistrer beaucoup de choses pour une raison quelconque, faites-le sur un thread séparé.
orkoden
4
Depuis Xcode 9.3, il y a un avertissement lors de l'utilisation de NSInteger comme argument de format avec %zd:Values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead
Rob MacEachern
2

La réponse acceptée est tout à fait raisonnable, conforme à la norme et correcte. Le seul problème est que cela ne fonctionne plus, ce qui est entièrement la faute d'Apple.

Le format% zd est le format standard C / C ++ pour size_t et ssize_t. Comme NSInteger et NSUInteger, size_t et ssize_t sont 32 bits sur un système 32 bits et 64 bits sur un système 64 bits. Et c'est pourquoi l'impression de NSInteger et NSUInteger à l'aide de% zd a fonctionné.

Cependant, NSInteger et NSUInteger sont définis comme "long" sur un système 64 bits et comme "int" sur un système 32 bits (qui est 64 contre 32 bits). Aujourd'hui, size_t est défini sur "long" sur tous les systèmes, ce qui est de la même taille que NSInteger (64 ou 32 bits), mais d'un type différent. Soit les avertissements d'Apple ont changé (il ne permet donc pas de passer le mauvais type à printf, même s'il a le bon nombre de bits), soit les types sous-jacents pour size_t et ssize_t ont changé. Je ne sais pas lequel, mais% zd a cessé de fonctionner il y a quelque temps. Il n'existe aujourd'hui aucun format permettant d'imprimer NSInteger sans avertissement sur les systèmes 32 et 64 bits.

Donc, la seule chose que vous pouvez faire malheureusement: utilisez% ld et transtypez vos valeurs de NSInteger en long, ou de NSUInteger en unsigned long.

Une fois que vous ne construisez plus pour 32 bits, vous pouvez simplement utiliser% ld, sans aucune distribution.

gnasher729
la source
0

Les formateurs proviennent de la fonction printf standard UNIX / POSIX. Utilisez % lu pour unsigned long ,% ld pour long,% lld pour long long et % llu pour unsigned long long . Essayez man printf sur la console, mais sur Mac, il est incomplet. Les pages de manuel Linux sont plus explicites http://www.manpages.info/linux/sprintf.3.html

Les deux avertissements ne peuvent être corrigés que par NSLog (@ "% lu", (unsigned long) arg); combiné avec un cast car le code sera compilé en 32 ET 64 bits pour iOS. Sinon, chaque compilation crée un avertissement distinct.

chat
la source