Die implizite Objective-C-Konvertierung verliert die Ganzzahlgenauigkeit 'NSUInteger' (auch bekannt als 'unsigned long') in die Warnung 'int'

187

Ich arbeite an einigen Übungen und habe eine Warnung erhalten, die besagt:

Die implizite Konvertierung verliert an ganzzahliger Genauigkeit: 'NSUInteger' (auch bekannt als 'unsigned long') in '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;
}

Bildschirmfoto

Affen junge
quelle

Antworten:

470

Die countMethode NSArraygibt ein NSUIntegerund auf der 64-Bit-OS X-Plattform zurück

  • NSUIntegerist definiert als unsigned longund
  • unsigned long ist eine 64-Bit-Ganzzahl ohne Vorzeichen.
  • int ist eine 32-Bit-Ganzzahl.

Ist intalso ein "kleinerer" Datentyp als NSUInteger, daher die Compiler-Warnung.

Siehe auch NSUInteger in der "Foundation Data Types Reference":

Beim Erstellen von 32-Bit-Anwendungen ist NSUInteger eine vorzeichenlose 32-Bit-Ganzzahl. Eine 64-Bit-Anwendung behandelt NSUInteger als 64-Bit-Ganzzahl ohne Vorzeichen.

Um diese Compiler-Warnung zu beheben, können Sie die lokale countVariable entweder als deklarieren

NSUInteger count;

oder (wenn Sie sicher sind, dass Ihr Array niemals mehr als 2^31-1Elemente enthält!), fügen Sie eine explizite Besetzung hinzu:

int count = (int)[myColors count];
Martin R.
quelle
19
Nur um es hinzuzufügen - ich habe diese Antwort abgelehnt, da ich in meinem Xcode 5-Projekt plötzlich eine Menge Warnungen und Fehler erhalten habe. Sie haben 64-Bit erwähnt, was mich dazu veranlasste, meine Build-Einstellungen zu überprüfen. Xcode hat es in den 64-Bit-Modus geändert, wodurch Fehler aufgetreten sind. Durch Zurücksetzen auf arvm7 wurden alle behoben.
Robert J. Clegg
1
@Tander gibt es einen Leistungsunterschied zwischen dem Kompilieren von 64bit und armv7?
Shaun Budhram
1
@ShaunBudhram Wie es aussieht, nein. Ich habe keinen Unterschied gesehen. Dies wird nur bei Apps einen Unterschied machen, die die CPU stark beanspruchen - Spiele zum Beispiel würden einen Vorteil beim Kompilieren für 64-Bit sehen.
Robert J. Clegg
7
"Ab dem 1. Februar 2015 müssen neue iOS-Apps, die in den App Store hochgeladen werden, 64-Bit-Unterstützung enthalten ..." - Apple Developer News und Updates, 20. Oktober 2014
Pang
2
@ JayprakashDubey: Apple sieht Ihre Compiler-Warnungen nicht, da Sie die binär kompilierte Anwendung an den App Store senden. Daher kann Ihre App aufgrund von Compiler-Warnungen nicht abgelehnt werden. Natürlich sollten Sie sie beheben, damit Ihre App richtig funktioniert.
Martin R
24

Im Gegensatz zu Martins Antwort ist das Casting auf int (oder das Ignorieren der Warnung) nicht immer sicher, selbst wenn Sie wissen, dass Ihr Array nicht mehr als 2 ^ 31-1 Elemente enthält. Nicht beim Kompilieren für 64-Bit.

Beispielsweise:

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
quelle
6
Sie haben Recht, dass das Casting des Ergebnisses indexOfObject:eine schlechte Idee wäre. Meine Antwort war für den spezifischen Code in der Frage gedacht, und die countMethode kann nicht zurückkehren NSNotFound. Ich habe nicht empfohlen, Warnungen auf int zu setzen oder Warnungen generell zu ignorieren. Entschuldigung, wenn das unklar war. Tatsächlich würde Ihr Beispielcode bei einer if (i == NSNotFound)Kompilierung für 64-Bit eine Warnung generieren , sodass das Problem nicht unbemerkt bleibt.
Martin R
@Adrian: Wenn es dir nichts ausmacht, was schlägst du dem Fragesteller vor?
Moonman239
@ moonman239 Im Allgemeinen würde ich nach Möglichkeit eine Variable des richtigen Typs verwenden (@ MartinRs erster Vorschlag), anstatt Casting (seinen zweiten). Wie er betont, ist das Casting in diesem speziellen Fall sicher, aber ich denke, es ist eine schlechte Angewohnheit, sich darauf einzulassen, da es unerwartete Konsequenzen haben kann (wie in meinem Beispiel). Ich habe gepostet, weil ich von dieser speziellen Situation gebissen wurde (obwohl das ein guter Punkt in Bezug auf die == Compiler-Warnung ist, die ich übersehen haben muss).
Adrian
2
Ich denke, count wird weitaus häufiger verwendet als indexOfObject, und es ist Unsinn, eine for-Schleife mit NSInteger aufzublähen, nur um keinen "schlechten" Codierungsstil zu haben. Sie sollten nur auf indexOfObject achten und sicherstellen, dass Sie dort NSIntegers verwenden. Alles, was einfach etwas zählt, ist als int in Ordnung, insbesondere innerhalb eines Methodenfokus
NikkyD
5

Ändern Sie den Schlüssel in Projekt> Build-Einstellung " typecheck-Aufrufe an printf / scanf : NO "

Erklärung: [Wie es funktioniert]

Überprüfen Sie die Aufrufe von printf und scanf usw., um sicherzustellen, dass die angegebenen Argumente Typen haben, die der angegebenen Formatzeichenfolge entsprechen, und dass die in der Formatzeichenfolge angegebenen Konvertierungen sinnvoll sind.

Hoffe es funktioniert

Andere Warnung

Die implizite Konvertierung von Ziel c verliert die ganzzahlige Genauigkeit 'NSUInteger' (auch bekannt als 'unsigned long') in 'int

Änderungsschlüssel " implizite Konvertierung in 32-Bit-Typ> Debug> * 64-Architektur: Nein "

[ Vorsicht: Möglicherweise wird eine andere Warnung zur 64-Bit-Architekturkonvertierung ungültig] .

Darshit Shah
quelle
Wenn Sie nur Ihre 32-Bit-Bibliothek in 64-Bit konvertieren möchten, ist dies eine vielversprechende Option.
San
2

Das expizite Casting auf "int" löst das Problem in meinem Fall. Ich hatte das gleiche Problem. So:

int count = (int)[myColors count];
Vladimir Despotovic
quelle
oder heißt es "implizit"? LOL :) In beiden Fällen hat es funktioniert.
Vladimir Despotovic