Типы Foundation при компиляции для arm64 и 32-битной архитектуры
Составив код приложения iOS для arm64, я столкнулся с интересной проблемой, связанной с различными базовыми типами для пользовательских типов Foundation. Скажем, я хочу напечатать f (или stringWithFormat) число, объявленное как NSUInteger
[NSString stringWithFormat:@"%u", _depth,
Это создаст предупреждение для arm64, потому что NSUInteger объявлен как unsigned long для arm64. Поэтому я должен заменить "% u" на "% lu", но теперь это становится недействительным при компиляции для архитектуры armv7 (s), потому что для 32-разрядных архитектур NSUInteger объявлено как unsigned int.
Я знаю, что предупреждение гласит: "NSUInteger не следует использовать как аргумент формата", поэтому давайте перейдем к floats:
typedef CGFLOAT_TYPE CGFloat;
в 64-битном CGFLOAT_TYPE double, а на 32-битном - float. Поэтому, делая что-то вроде этого:
- (void)foo:(CGFloat)value;
а затем
[self foo:10.0f];
[self foo:10.0];
Будет выдавать предупреждение при компиляции для двух архитектур. В 32-битной архитектуре второй вызов неверен (преобразование из double в float), в 64-битной архитектуре, первая конвертирует float в double (что нормально, но все равно не хорошо).
Хотелось бы услышать ваши мысли по этой проблеме.
Ответы
Ответ 1
Один (по общему признанию, ужасный) подход, который я видел, используется, чтобы использовать магию #define
и компилировать литеральную литературную конкатенацию. Вот так:
// In your prefix header or something
#if __LP64__
#define NSI "ld"
#define NSU "lu"
#else
#define NSI "d"
#define NSU "u"
#endif
// Then later you can use these like this...
NSString* foo = [NSString stringWithFormat:@"%"NSU" things in the array.", array.count]);
Довольно ужасно, но он работает.
Другим, казалось бы, более распространенным подходом является просто повышение значения для более крупного типа на каждой платформе, например:
NSString* foo = [NSString stringWithFormat:@"%lu things in the array.", (unsigned long)array.count]);
Совсем недавно (т.е. с момента появления нового синтаксиса с сокращением бокса), я обнаружил, что я ленив и начал просто бокс, как это:
NSString* foo = [NSString stringWithFormat:@"%@ things in the array.", @(array.count)]);
Может быть, лучший способ, но те, что я видел больше всего.