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