Типы фундаментов при компиляции для 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)]);

Может быть, есть и лучший способ, но это те, которые я видел больше всего.

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