Спецификатор 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. В противном случае каждая компиляция создает отдельное предупреждение.

Другие вопросы по тегам