NSLog / printf specifier untuk NSInteger?

131

A NSIntegeradalah 32 bit pada platform 32-bit, dan 64 bit pada platform 64-bit. Apakah ada NSLogspecifier yang selalu cocok dengan ukuran NSInteger?

Mempersiapkan

  • Xcode 3.2.5
  • llvm 1.6 compiler (ini penting; gcc tidak melakukan ini)
  • GCC_WARN_TYPECHECK_CALLS_TO_PRINTF dihidupkan

Itu membuat saya sedih di sini:

#import <Foundation/Foundation.h>

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

Untuk kode 32 bit, saya perlu %dspecifier. Tetapi jika saya menggunakan %dspecifier, saya mendapat peringatan ketika mengkompilasi untuk 64 bit menyarankan saya gunakan %ldsebagai gantinya.

Jika saya gunakan %lduntuk mencocokkan ukuran 64 bit, ketika mengkompilasi kode 32 bit saya mendapatkan peringatan yang menyarankan saya gunakan %dsebagai gantinya.

Bagaimana cara saya memperbaiki kedua peringatan sekaligus? Apakah ada specifier yang bisa saya gunakan yang berfungsi baik?

Ini juga berdampak [NSString stringWithFormat:]dan [[NSString alloc] initWithFormat:].

Steven Fisher
sumber

Jawaban:

296

Jawaban yang diperbarui:

Anda dapat menggunakan zdan tpengubah untuk menangani NSIntegerdan NSUIntegertanpa peringatan, di semua arsitektur.

Anda ingin menggunakan %zduntuk ditandatangani, %tuuntuk unsigned, dan %txuntuk hex.

Informasi ini berasal dari Greg Parker .


Jawaban asli:

Pendekatan resmi yang disarankan adalah untuk digunakan %ldsebagai specifier Anda, dan untuk melemparkan argumen yang sebenarnya ke a long.

Lily Ballard
sumber
6
Ini jelas cara untuk pergi, tapi saya pikir saya akan menggunakan static inline NSIntToLong(NSInteger i) {return (long)i;}. Ini menghindari pemeriksaan penonaktifan tipe sepenuhnya (yaitu jika jenis i berubah).
Steven Fisher
3
Pemikiran yang bagus oleh @ steven-fisher. Hindari peringatan dengan:static inline long NSIntToLong(NSInteger i) {return (long)i;}
Erik
3
Anda juga dapat membuat NSNumber dan mencatatnya. NSLog(@"%@",@(mynsint)); stackoverflow.com/questions/20355439/…
orkoden
2
@KevinBallard Ini seharusnya tidak menjadi masalah kinerja yang serius. Anda seharusnya tidak menggunakan banyak NSLog dalam kode produksi. Jika Anda harus mencatat banyak hal karena beberapa alasan, lakukan di utas terpisah.
orkoden
4
Pada Xcode 9.3 ada peringatan saat menggunakan NSInteger sebagai argumen format dengan %zd:Values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead
Rob MacEachern
2

Jawaban yang diterima benar-benar masuk akal, sesuai standar, dan benar. Satu-satunya masalah adalah bahwa itu tidak berfungsi lagi, yang sepenuhnya merupakan kesalahan Apple.

Format% zd adalah format standar C / C ++ untuk size_t dan ssize_t. Seperti NSInteger dan NSUInteger, size_t dan ssize_t adalah 32 bit pada sistem 32 bit, dan 64 bit pada sistem 64 bit. Dan itu sebabnya pencetakan NSInteger dan NSUInteger menggunakan% zd bekerja.

Namun, NSInteger dan NSUInteger didefinisikan sebagai "panjang" pada sistem 64 bit, dan sebagai "int" pada sistem 32 bit (yaitu 64 vs 32 bit). Hari ini, size_t didefinisikan pada "lama" pada semua sistem, yang merupakan ukuran yang sama seperti NSInteger (baik 64 atau 32 bit), tapi jenis yang berbeda. Entah peringatan Apple telah berubah (jadi itu tidak memungkinkan melewatkan jenis yang salah ke printf, meskipun memiliki jumlah bit yang tepat), atau jenis yang mendasari untuk size_t dan ssize_t telah berubah. Saya tidak tahu yang mana, tetapi% zd berhenti bekerja beberapa waktu yang lalu. Tidak ada format hari ini yang akan mencetak NSInteger tanpa peringatan pada sistem 32 dan 64 bit.

Jadi satu-satunya hal yang dapat Anda lakukan sayangnya: Gunakan% ld, dan berikan nilai Anda dari NSInteger ke long, atau dari NSUInteger ke long unsigned.

Setelah Anda tidak membuat 32 bit lagi, Anda bisa menggunakan% ld, tanpa gips.

gnasher729
sumber
0

Pemformat berasal dari fungsi printf standar UNIX / POSIX. Gunakan % lu untuk panjang yang tidak ditandatangani ,% ld untuk panjang,% lld untuk panjang panjang, dan % llu untuk panjang tidak ditandatangani . Coba printf man di konsol, tetapi pada Mac itu tidak lengkap. Linux manpages lebih eksplisit http://www.manpages.info/linux/sprintf.3.html

Kedua peringatan hanya dapat diperbaiki oleh NSLog (@ "% lu", (unsigned long) arg); dikombinasikan dengan para pemain sebagai kode akan dikompilasi dalam 32 DAN 64 bit untuk iOS. Kalau tidak, setiap kompilasi membuat peringatan terpisah.

kucing
sumber