Почему переменная NSInteger должна быть отброшена дольше при использовании в качестве аргумента формата?

NSInteger myInt = 1804809223;
NSLog(@"%i", myInt); <==== 

Приведенный выше код создает ошибку:

Values of type "NSInteger" should not be used as format arguments: add an explicit cast to 'long' instead.

Правильное сообщение NSLog на самом деле NSLog(@"%lg", (long) myInt); Почему мне нужно преобразовать целочисленное значение myInt в long, если я хочу, чтобы значение отображалось?

Ответ 1

Вы получаете это предупреждение, если компилируете в OS X (64-разрядный), потому что на этой платформе NSInteger определяется как long и является 64-разрядным целым числом. Формат %i, с другой стороны, для int, который является 32-битным. Поэтому формат и фактический параметр не совпадают по размеру.

Так как NSInteger - 32-разрядный или 64-разрядный, в зависимости от платформы компилятор рекомендует для добавления приведения к long в целом.

Обновление. Так как iOS 7 теперь поддерживает 64-разрядную версию, вы можете получить такое же предупреждение при компиляции для iOS.

Ответ 2

Вам не нужно приводить что-либо, если ваши спецификаторы формата соответствуют вашим типам данных. См. ответ Martin R для получения подробной информации о том, как NSInteger определяется в терминах нативных типов.

Таким образом, для кода, предназначенного для построения в 64-битных средах, вы можете написать свои операторы журнала следующим образом:

NSLog(@"%ld",  myInt); 

в то время как для 32-битных сред вы можете написать:

NSLog(@"%d",  myInt); 

и все будет работать без приведения.

В любом случае, одной из причин использования приведений является то, что хороший код имеет тенденцию переноситься на разные платформы, и если вы приведете свои переменные явным образом, он будет скомпилирован без ошибок как на 32-, так и на 64-битной версии:

NSLog(@"%ld",  (long)myInt);

И обратите внимание, что это верно не только для операторов NSLog, которые, в конце концов, просто средства отладки, но также для [NSString stringWithFormat:] и различных производных сообщений, которые являются законными элементами производственного кода.

Ответ 3

Вместо передачи NSInteger в NSLog просто передайте NSNumber. Это обойдёт все броски и выберет нужный спецификатор формата строки.

NSNumber foo = @9000;
NSLog(@"foo: %@", foo);
NSInteger bar = 9001;
NSLog(@"bar: %@", @(bar));

Он также работает для NSUIntegers, не беспокоясь об этом. См. Ответ NSInteger и NSUInteger в смешанной среде 64 бит /32 бит

Ответ 4

Он сохраняет предупреждение при использовании NSLog(@"%ld", (long)myInt);, но останавливает предупреждение после объявления изменения в long myInt = 1804809223; в iOS 10.

Ответ 5

OS X использует несколько типов данных - NSInteger, NSUInteger, CGFloat и CFIndex - для обеспечения согласованного способа представления значений в 32- и 64-разрядных средах. В 32-разрядной среде NSInteger и NSUInteger определяются как int и unsigned int, соответственно. В 64-разрядных средах NSInteger и NSUInteger определяются как long и unsigned long, соответственно. Чтобы избежать необходимости использования разных спецификаторов типа printf в зависимости от платформы, вы можете использовать спецификаторы, показанные в этой ссылке для 32-разрядных и 64-разрядная среда.