Почему переменная 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-разрядная среда.