Konversi implisit Objective-C kehilangan presisi integer 'NSUInteger' (alias 'unsigned long') menjadi peringatan 'int'

187

Saya sedang mengerjakan beberapa latihan dan mendapat peringatan yang menyatakan:

Konversi implisit kehilangan presisi integer: 'NSUInteger' (alias 'unsigned long') menjadi '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;
}

Tangkapan layar

monyet
sumber

Jawaban:

470

The countmetode NSArraypengembalian sebuah NSUInteger, dan pada 64-bit OS X platform yang

  • NSUIntegerdidefinisikan sebagai unsigned long, dan
  • unsigned long adalah integer unsigned 64-bit.
  • int adalah integer 32-bit.

Jadi intadalah tipe data "lebih kecil" dari NSUInteger, oleh karena itu peringatan kompiler.

Lihat juga NSUInteger di "Referensi Tipe Data Yayasan":

Saat membangun aplikasi 32-bit, NSUInteger adalah integer 32-bit yang tidak ditandatangani. Aplikasi 64-bit memperlakukan NSUInteger sebagai integer 64-bit yang tidak ditandatangani.

Untuk memperbaiki peringatan kompiler itu, Anda bisa mendeklarasikan countvariabel lokal sebagai

NSUInteger count;

atau (jika Anda yakin array Anda tidak akan pernah mengandung lebih dari 2^31-1elemen!), tambahkan gips eksplisit:

int count = (int)[myColors count];
Martin R
sumber
19
Hanya untuk menambahkan - Saya memilih jawaban ini karena saya menerima banyak peringatan dan kesalahan tiba-tiba dalam proyek Xcode 5 saya. Anda menyebutkan 64bit yang membuat saya melihat pengaturan build saya. Xcode mengubahnya menjadi mode 64bit yang memunculkan kesalahan. Mengubahnya kembali ke arvm7 memperbaiki semuanya.
Robert J. Clegg
1
@Tand apakah ada perbedaan kinerja antara kompilasi 64bit vs armv7?
Shaun Budhram
1
@ShaunBudhram Dengan kelihatannya tidak. Saya belum melihat perbedaan. Ini hanya akan membuat perbedaan dalam aplikasi yang banyak menggunakan CPU - game misalnya akan melihat manfaat kompilasi untuk 64 bit.
Robert J. Clegg
7
"Mulai 1 Februari 2015, aplikasi iOS baru yang diunggah ke App Store harus menyertakan dukungan 64-bit ..." - Berita dan Pembaruan Pengembang Apple, 20 Oktober 2014
Pang
2
@JayprakashDubey: Apple tidak melihat peringatan kompiler Anda karena Anda mengirimkan aplikasi kompilasi biner ke App Store. Karenanya aplikasi Anda tidak dapat ditolak karena peringatan kompiler. Tentu saja Anda harus memperbaikinya untuk membuat aplikasi Anda berfungsi dengan benar.
Martin R
24

Bertentangan dengan jawaban Martin, memilih ke int (atau mengabaikan peringatan) tidak selalu aman bahkan jika Anda tahu array Anda tidak memiliki lebih dari 2 ^ 31-1 elemen. Tidak ketika mengkompilasi untuk 64-bit.

Sebagai contoh:

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
sumber
6
Anda benar bahwa casting hasil indexOfObject:akan menjadi ide yang buruk. Jawaban saya dimaksudkan untuk kode spesifik dalam pertanyaan, dan countmetode ini tidak dapat kembali NSNotFound. Saya tidak merekomendasikan untuk menggunakan int atau mengabaikan peringatan secara umum. Maaf kalau itu tidak jelas. Bahkan kode sampel Anda akan menghasilkan peringatan if (i == NSNotFound)jika dikompilasi untuk 64-bit, sehingga masalahnya tidak akan luput dari perhatian.
Martin R
@Adrian: Jika Anda tidak keberatan, apa yang Anda sarankan dilakukan oleh si penanya?
moonman239
@ moonman239 Secara umum, saya akan menggunakan variabel dari tipe yang benar jika mungkin (@ saran pertama MartinR) sebagai lawan casting (yang kedua). Seperti yang dia tunjukkan, casting aman dalam kasus khusus ini, tapi saya pikir itu kebiasaan buruk untuk masuk, karena dapat memiliki konsekuensi yang tidak terduga (seperti dalam contoh saya). Saya memposting karena saya telah digigit oleh situasi khusus ini (walaupun itu poin bagus tentang peringatan == compiler, yang pasti saya lewatkan).
Adrian
2
i think count akan digunakan jauh lebih sering daripada indexOfObject, dan membengkak untuk-loop dengan NSInteger hanya tidak memiliki gaya pengkodean "miskin" adalah omong kosong. Anda harus memperhatikan semata-mata untuk indexOfObject dan pastikan Anda menggunakan NSIntegers di sana, semua yang hanya menghitung sesuatu baik-baik saja sebagai int, terutama dalam fokus metode
NikkyD
5

Ubah kunci dalam Proyek> Pengaturan Bangun " ketik panggilan cek ke printf / scanf : TIDAK "

Penjelasan: [Cara kerjanya]

Periksa panggilan ke printf dan scanf, dll., Untuk memastikan bahwa argumen yang diberikan memiliki tipe yang sesuai dengan format string yang ditentukan, dan bahwa konversi yang ditentukan dalam format string masuk akal.

Semoga berhasil

Peringatan lainnya

obyektif c konversi implisit kehilangan presisi integer 'NSUInteger' (alias 'unsigned long') menjadi 'int

Ubah kunci " konversi implisit ke Jenis 32bit> Debug> * 64 arsitektur: Tidak "

[ hati-hati: Ini dapat membatalkan peringatan lain konversi arsitektur 64 Bit] .

Darshit Shah
sumber
jika Anda hanya ingin mengubah pustaka 32 bit Anda menjadi 64 bit, ini adalah opsi yang menjanjikan.
San
2

Melakukan casting expicit ke "int" memecahkan masalah dalam kasus saya. Saya memiliki masalah yang sama. Begitu:

int count = (int)[myColors count];
Vladimir Despotovic
sumber
atau itu disebut "implisit"? LOL :) Dalam kedua kasus itu, itu berhasil.
Vladimir Despotovic