Спецификатор NSLog/printf для NSInteger?
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:]
.
Ответы
Ответ 1
Обновленный ответ:
С текущим Xcode вы можете использовать модификаторы z
и t
для обработки NSInteger
и NSUInteger
без предупреждений на всех архитектурах.
Вы хотите использовать %zd
для подписанных, %tu
для unsigned и %tx
для hex.
Эта информация предоставляется любезно Грег Паркер.
Оригинальный ответ:
официальный рекомендуемый подход заключается в использовании %ld
в качестве вашего спецификатора и приведения фактического аргумента в long
.
Ответ 2
Принятый ответ является абсолютно обоснованным, стандартным и правильным. Единственная проблема заключается в том, что он больше не работает, что полностью вина Apple.
Формат% zd является стандартным форматом C/C++ для size_t и ssize_t. Как NSInteger и NSUInteger, size_t и ssize_t являются 32-разрядными в 32-разрядной системе и 64-разрядными в 64-разрядной системе. И вот почему печать NSInteger и NSUInteger с использованием% zd работала.
Однако NSInteger и NSUInteger определены как "long" в 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 без приведения.
Ответ 3
Форматировщики поступают из стандартной функции printf UNIX/POSIX. Используйте % lu для unsigned long,% ld для длинных,% lld для долгого времени и % llu для unsigned long long. Попробуйте man printf на консоли, но на Mac он неполный. Линукс файлы более явные http://www.manpages.info/linux/sprintf.3.html
Оба предупреждения могут быть установлены только NSLog (@ "% lu", (unsigned long) arg); в сочетании с литой, поскольку код будет скомпилирован в 32 и 64 бит для iOS. В противном случае каждая компиляция создает отдельное предупреждение.