Спецификатор 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вместо него.

Если я использую %ldдля соответствия 64-битному размеру, при компиляции для 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
Роб Макихерн,
2

Принятый ответ абсолютно разумен, соответствует стандартам и верен. Единственная проблема в том, что он больше не работает, и это полностью вина Apple.

Формат% zd - это стандартный формат C / C ++ для size_t и ssize_t. Подобно NSInteger и NSUInteger, size_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 в unsigned long.

Если вы больше не собираете 32-битную версию, вы можете просто использовать% ld без каких-либо преобразований.

gnasher729
источник
0

Средства форматирования поступают из стандартной функции printf UNIX / POSIX. Используйте % lu для беззнакового long ,% ld для long,% lld для long long и % llu для unsigned long long . Попробуйте man printf на консоли, но на Mac он будет неполным. Справочные страницы linux более подробны http://www.manpages.info/linux/sprintf.3.html

Оба предупреждения могут быть исправлены только NSLog (@ "% lu", (unsigned long) arg); в сочетании с приведением, поскольку код будет скомпилирован в 32- и 64-разрядной версии для iOS. В противном случае каждая компиляция создает отдельное предупреждение.

кошка
источник