Специфікатор NSLog / printf для NSInteger?


131

A NSInteger- 32 біти на 32-бітних платформах, а 64 біт - на 64-бітних платформах. Чи є NSLogспецифікатор, який завжди відповідає розміру NSInteger?

Налаштування

  • Xcode 3.2.5
  • компілятор llvm 1.6 (це важливо; gcc цього не робить)
  • GCC_WARN_TYPECHECK_CALLS_TO_PRINTF включено

Це викликає у мене трохи горя тут:

#import <Foundation/Foundation.h>

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

Для 32-бітного коду мені потрібен %dспецифікатор. Але якщо я використовую %dспецифікатор, я отримую попередження, коли компілюю 64-бітну пропозицію використовувати %ldзамість цього.

Якщо я використовую %ld64-бітовий розмір, під час компіляції 32-бітового коду я отримую попередження про те, що я використовую %dзамість цього.

Як виправити обидва попередження одночасно? Чи є специфікатор, яким я можу скористатися, який працює на будь-якому?

Це також впливає [NSString stringWithFormat:]і [[NSString alloc] initWithFormat:].

Відповіді:


296

Оновлена ​​відповідь:

Ви можете використовувати zі tмодифікатори для обробки NSIntegerта NSUIntegerбез попереджень у всіх архітектурах.

Ви хочете використовувати %zdдля підписаних, %tuнепідписаних та %txшістнадцяткових.

Ця інформація надходить з люб’язності Грега Паркера .


Оригінальна відповідь:

Офіційне рекомендований підхід полягає у використанні в %ldякості специфікатор і кинути фактичний аргумент до long.


6
Це, безумовно, шлях, але я думаю, що я міг би скористатися static inline NSIntToLong(NSInteger i) {return (long)i;}. Це дозволяє уникнути повного відключення перевірки типу (тобто якщо тип i змінюється).
Стівен Фішер

3
Гарне мислення від @ steven-fisher. Уникайте попередження з:static inline long NSIntToLong(NSInteger i) {return (long)i;}
Ерік

3
Ви також можете створити NSNumber і записати це. NSLog(@"%@",@(mynsint)); stackoverflow.com/questions/20355439 / ...
orkoden

2
@KevinBallard Це не повинно бути серйозним питанням продуктивності. У виробничому коді все одно не слід використовувати багато NSLog. Якщо вам доведеться вносити багато речей з певних причин, зробіть це окремою темою.
orkoden

4
Станом на Xcode 9.3 є попередження при використанні NSInteger в якості аргументу формату %zd:Values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead
Rob MacEachern

2

Прийнята відповідь абсолютно розумна, вона відповідає стандарту та правильна. Єдина проблема полягає в тому, що вона більше не працює, що є повністю виною Apple.

Формат% zd - це стандартний формат C / C ++ для size_t та ssize_t. Як і NSInteger і NSUInteger, розмір_t та ssize_t є 32-бітовими в 32-бітовій системі та 64-бітовими в 64-бітовій системі. І тому друк NSInteger та NSUInteger за допомогою% zd працював.

Однак NSInteger та NSUInteger визначаються як "довгі" у 64-бітовій системі та як "int" у 32-бітовій системі (що становить 64 проти 32 біт). Сьогодні size_t визначається на "long" у всіх системах, який має той самий розмір, що і NSInteger (або 64, або 32 біт), але іншого типу. Або попередження Apple змінилися (тому він не дозволяє передавати неправильний тип printf, навіть якщо він має потрібну кількість біт), або зміни типів для size_t та ssize_t змінилися. Я не знаю, який з них, але% zd перестав працювати деякий час тому. Сьогодні не існує формату, який би друкував NSInteger без попередження для обох 32 та 64 бітних систем.

Отже, єдине, що ви можете зробити, на жаль: Використовуйте% ld і передавайте свої значення від NSInteger до long або від NSUInteger до long unsigned.

Після того, як ви більше не будуєте 32-бітні, ви можете просто використовувати% ld, без будь-якого складу.


0

Форматори походять від стандартної функції UNIX / POSIX printf. Використовуйте % lu для довго не підписаних ,% ld для довгих,% lld для довгих довгих, і % llu для неподписаних довгих довгих . Спробуйте man printf на консолі, але на Mac це неповно. Ліцензування Linux є більш чіткими http://www.manpages.info/linux/sprintf.3.html

Обидва попередження можуть бути виправлені лише NSLog (@ "% lu", (unsigned long) arg); у поєднанні з кастом, оскільки код буде складено в 32 AND 64 біт для iOS. Інакше кожна компіляція створює окреме попередження.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.