La conversion implicite Objective-C perd la précision entière 'NSUInteger' (aka 'unsigned long') en avertissement 'int'

187

Je travaille sur quelques exercices et j'ai un avertissement qui déclare:

La conversion implicite perd la précision entière: 'NSUInteger' (aka 'unsigned long') en 'int'

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{
    @autoreleasepool {

        NSArray *myColors;

        int i;
        int count;

        myColors = @[@"Red", @"Green", @"Blue", @"Yellow"];

        count = myColors.count; //  <<< issue warning here

        for (i = 0; i < count; i++)

        NSLog (@"Element %i = %@", i, [myColors objectAtIndex: i]);
    }

    return 0;
}

Capture d'écran

le petit singe
la source

Réponses:

470

La countméthode de NSArrayretourne un NSUInteger, et sur la plate-forme OS X 64 bits

  • NSUIntegerest défini comme unsigned long, et
  • unsigned long est un entier non signé de 64 bits.
  • int est un entier de 32 bits.

Il en intva de même pour un type de données "plus petit" que NSUInteger, par conséquent, l'avertissement du compilateur.

Voir aussi NSUInteger dans le «Foundation Data Types Reference»:

Lors de la création d'applications 32 bits, NSUInteger est un entier non signé 32 bits. Une application 64 bits traite NSUInteger comme un entier 64 bits non signé.

Pour corriger cet avertissement du compilateur, vous pouvez soit déclarer la countvariable locale comme

NSUInteger count;

ou (si vous êtes sûr que votre tableau ne contiendra jamais plus que des 2^31-1éléments!), ajoutez un cast explicite:

int count = (int)[myColors count];
Martin R
la source
19
Juste pour ajouter - j'ai voté pour cette réponse car j'ai reçu un tas d'avertissements et d'erreurs tout d'un coup dans mon projet Xcode 5. Vous avez mentionné 64 bits, ce qui m'a amené à examiner mes paramètres de construction. Xcode l'a changé en mode 64 bits, ce qui a généré des erreurs. Le ramener à arvm7 les a tous corrigés.
Robert J. Clegg
1
@Tander Y a-t-il une différence de performances entre la compilation 64 bits et armv7?
Shaun Budhram
1
@ShaunBudhram Par son apparence, non. Je n'ai vu aucune différence. Cela ne fera une différence que dans les applications qui utilisent fortement le processeur - les jeux par exemple verraient un avantage à compiler pour 64 bits.
Robert J. Clegg
7
«À compter du 1er février 2015, les nouvelles applications iOS téléchargées sur l'App Store doivent inclure la prise en charge 64 bits ...» - Apple Developer News and Updates, 20 octobre 2014
Pang
2
@JayprakashDubey: Apple ne voit pas les avertissements de votre compilateur car vous soumettez l'application compilée binaire à l'App Store. Par conséquent, votre application ne peut pas être rejetée en raison des avertissements du compilateur. Bien sûr, vous devez les corriger pour que votre application fonctionne correctement.
Martin R
24

Contrairement à la réponse de Martin, transtyper en int (ou ignorer l'avertissement) n'est pas toujours sûr même si vous savez que votre tableau ne contient pas plus de 2 ^ 31-1 éléments. Pas lors de la compilation pour 64 bits.

Par exemple:

NSArray *array = @[@"a", @"b", @"c"];

int i = (int) [array indexOfObject:@"d"];
// indexOfObject returned NSNotFound, which is NSIntegerMax, which is LONG_MAX in 64 bit.
// We cast this to int and got -1.
// But -1 != NSNotFound. Trouble ahead!

if (i == NSNotFound) {
    // thought we'd get here, but we don't
    NSLog(@"it's not here");
}
else {
    // this is what actually happens
    NSLog(@"it's here: %d", i);

    // **** crash horribly ****
    NSLog(@"the object is %@", array[i]);
}
Adrian
la source
6
Vous avez raison de dire que la diffusion du résultat indexOfObject:serait une mauvaise idée. Ma réponse était destinée au code spécifique de la question et la countméthode ne peut pas retourner NSNotFound. Je n'ai pas recommandé de cast en int ou d'ignorer les avertissements en général. Désolé si ce n'était pas clair. En fait, votre exemple de code générerait un avertissement à if (i == NSNotFound)s'il était compilé pour 64 bits, de sorte que le problème ne passerait pas inaperçu.
Martin R
@Adrian: Si cela ne vous dérange pas, que suggérez-vous au demandeur de faire?
moonman239
@ moonman239 En général, j'utiliserais une variable du type correct si possible (la première suggestion de @ MartinR) par opposition au casting (sa seconde). Comme il le souligne, le casting est sûr dans ce cas particulier, mais je pense que c'est une mauvaise habitude à prendre, car cela peut avoir des conséquences inattendues (comme dans mon exemple). J'ai posté parce que j'ai été mordu par cette situation spécifique (bien que ce soit un bon point à propos de l'avertissement du compilateur ==, que j'ai dû manquer).
Adrian
2
Je pense que count sera utilisé beaucoup plus souvent que indexOfObject, et gonfler une boucle for avec NSInteger simplement pour ne pas avoir un style de codage «pauvre» est absurde. Vous devez surveiller uniquement indexOfObject et vous assurer que vous utilisez NSIntegers là-bas, tout ce qui compte simplement quelque chose est bien comme int, en particulier dans un focus sur les méthodes
NikkyD
5

Modifier la clé dans Projet> Paramètre de construction " vérifier les appels à printf / scanf : NON "

Explication: [Comment ça marche]

Vérifiez les appels à printf et scanf, etc., pour vous assurer que les arguments fournis ont des types appropriés à la chaîne de format spécifiée et que les conversions spécifiées dans la chaîne de format ont un sens.

J'espère que ça marche

Autre avertissement

objectif c la conversion implicite perd la précision entière 'NSUInteger' (aka 'unsigned long') en 'int

Modifier la clé " conversion implicite en 32 bits Type> Débogage> architecture * 64: Non "

[ attention: cela peut annuler tout autre avertissement de conversion d'architecture 64 bits] .

Darshit Shah
la source
si vous vouliez simplement convertir votre bibliothèque 32 bits en 64 bits, c'est une option prometteuse.
San
2

Faire le casting expicite vers "int" résout le problème dans mon cas. J'ai eu le même problème. Alors:

int count = (int)[myColors count];
Vladimir Despotovic
la source
ou est-il appelé «implicite»? LOL :) Dans les deux cas, cela a fonctionné.
Vladimir Despotovic