Типы фундаментов при компиляции для 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 не должен использоваться в качестве аргумента формата", поэтому давайте перейдем к плавающим значениям:
typedef CGFLOAT_TYPE CGFloat;
на 64-битном CGFLOAT_TYPE является двойным, а на 32-битном - с плавающей запятой. Поэтому делаем что-то вроде этого:
- (void)foo:(CGFloat)value;
а потом
[self foo:10.0f];
[self foo:10.0];
Будет по-прежнему выдавать предупреждение при компиляции для двух архитектур. В 32-битной архитектуре второй вызов некорректен (преобразование из двойного в число с плавающей запятой), в 64-битной архитектуре первый преобразует число с плавающей запятой в двойное (что нормально, но все же не хорошо).
Хотелось бы услышать ваши мысли по этой проблеме.
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)]);
Может быть, есть и лучший способ, но это те, которые я видел больше всего.