Преобразование существующего приложения к 64-разрядному

Для помощи Вам в преобразовании проекта существующего приложения к 64-разрядному Apple обеспечивает сценарий, выполняющий большую часть работы. Сценарий выполняет оперативные замены относительно файлов исходного кода согласно ряду правил. Однако после выполнения сценария, все еще необходимо смотреть на все, что изменилось или было отмечено, и фиксируйте его при необходимости. Эта процедура, описанная ниже работ также для существующих проектов платформы, сменных проектов или других проектов.

Процедура преобразования

Запустите путем устранения предупреждений сборки, что проект в настоящее время генерирует; это упростит фокусироваться на предупреждениях, которые являются определенными для 64-разрядных проблем преобразования. Также сохраните копию проекта в случае, если что-то идет не так, как надо в процессе преобразования, и необходимо запустить. Тогда в Терминальной оболочке выполняет сценарий преобразования ConvertCocoa64 расположенный в /Developer/Extras/64BitConversion/. Можно выполнить сценарий на определенном источнике и заголовочных файлах, как в этом примере:

/Developer/Extras/64BitConversion/ConvertCocoa64 Controller.h Controller.m CustomView.h CustomView.h

Или можно выполнить его на всех .h и .m файлы в Вашем проекте, как в этом примере:

/Developer/Extras/64BitConversion/ConvertCocoa64 `find . -name '*.[hm]' | xargs`

Когда сценарий работает, он делает следующие вещи:

После того, как сценарий завершает обработку всех файлов, запустите приложение разработки FileMerge на каждом измененном файле и неизменной версии того же файла. FileMerge визуально выделяет каждый измененный раздел кода. После того, чтобы читать Вещи Искать Во время Преобразования, оцените каждый из этих разделов плюс предупреждения, сгенерированные сценарием, и внесите дальнейшие изменения при необходимости.

Помните, что любое 64-разрядное изменение, которое Вы вносите, должно помочь сохранить совместимость на уровне двоичных кодов Вашей исполнимой программы проекта в 32-разрядных системах. Необходимо использовать конструкции в Таблице 3-1 для отделения разделов кода условно для каждой архитектуры: PowerPC по сравнению с Intel и 32-разрядный по сравнению с 64-разрядным.

Табличные 3-1  Макросы для условного кода архитектуры

Макрос

Комментарий

#if __LP64__

PowerPC или 64-разрядный Intel. Необходимо использовать это для большинства 64-разрядных изменений.

#ifdef __ppc__

32-разрядный PowerPC

#ifdef __ppc64__

64-разрядный PowerPC

#ifdef __i386__

32-разрядный Intel

#ifdef __x86_64__

64-разрядный Intel

#ifdef __BIG_ENDIAN__

Архитектура с обратным порядком байтов

Вещи искать во время преобразования

Когда сценарий преобразования обрабатывает исходный или заголовочный файл, он часто вставляет предупреждения в код, чтобы предупредить Вас к изменениям, что Вам, возможно, придется сделать или ловушки, которых необходимо попытаться избежать. Эти предупреждения объяснены в следующих разделах.

Введите спецификаторы

Действие сценария: Предупреждает о потенциальных проблемах; может генерировать ложные отрицания.

Как правило, в 32-разрядном коде Вы используете %d спецификатор для форматирования int значения в функциях такой как printf, NSAssert, и NSLog, и в методах такой как stringWithFormat:. Но с NSInteger, который на 64-разрядной архитектуре является тем же размером как long, необходимо использовать %ld спецификатор. Если Вы не создаете 32-разрядный как 64-разрядный, эти спецификаторы генерирует предупреждения компилятора в 32-разрядном режиме. Для предотвращения этой проблемы можно бросить значения к long или unsigned long, как надлежащий. Например:

NSInteger i = 34;
printf("%ld\n", (long)i);

Таблица 3-2 перечисляет спецификаторы для форматирования 64-разрядных типов.

Табличные 3-2  спецификаторы Типа для 64-разрядных типов

Ввести

Спецификатор

Комментарии

NSInteger

%ld или %lx

Бросьте значение к long.

NSUInteger

%lu или %lx

Бросьте значение к unsigned long.

CGFloat

%f или %g

%f работы для плаваний и удваиваются, форматируя (но не сканируя).

CFIndex

%ld или %lx

Бросьте значение к long.

long long

%lld или %llx

long long является 64-разрядным и на 32-разрядной и на 64-разрядной архитектуре.

unsigned long long

%llu или %llx

unsigned long long является 64-разрядным и на 32-разрядной и на 64-разрядной архитектуре.

Сценарий также вставляет предупреждения в связанный случай сканирования функций такой как scanf, но они представляют дополнительную тонкость. Необходимо различить float и double типы, с помощью %f для float и %lf для double. Не использовать CGFloat параметр в scanf- введите функции; вместо этого используйте a double параметр и присваивается double оцените a CGFloat переменная. Например,

double tmp;
sscanf(str, "%lf", &tmp);
CGFloat imageWidth = tmp;

Невключенная архивация

Действие сценария: Предупреждает относительно потенциальных проблем

Старый стиль архивации Какао полагается на последовательность закодированных и декодируемых свойств, а не ключей как средние значения для идентификации заархивированных значений; необходимо декодировать свойства в том же порядке их кодирования. Разработчики призваны переехать от этой архивации старого стиля до включенной архивации. Однако приложениям, вероятно, придется считать архивы старого стиля, таким образом, они не могут отказаться от этой архивации без ключа в целом. И с 64-разрядной точки зрения Вы не можете изменить эти архивы для размещения больших значений, потому что это лишило бы возможности более старые версии приложения декодировать архив.

При чтении архивов старого стиля помните, что целые числа, закодированные с «i» и «l» (маленький L) кодирующие тип спецификаторы, являются 32-разрядными даже на 64-разрядной архитектуре. Для указания 64-разрядных целых чисел, необходимо использовать «q» кодирующий тип спецификатор. Но если Вы вводите переменную экземпляра как NSInteger значение, следующая попытка декодирования не будет работать над 64-разрядной архитектурой:

// Header file
NSInteger bitsPerSample;  // instance variable
 
// Implementation file
[coder decodeValuesOfObjCTypes:"i", &bitsPerSample];

Один способ обойти эту проблему состоит в том, чтобы использовать локальную переменную для промежуточного значения, затем присвоить это значение NSInteger переменная экземпляра после декодирования.

// Header file
NSInteger bitsPerSample;
// Implementation file
int tmp;
[coder decodeValuesOfObjCTypes:"i", &tmp];
bitsPerSample = tmp;

Можно использовать тот же промежуточно-переменный метод для кодирования NSInteger значения (как 32-разрядный), а также декодирование их.

Переменные экземпляра, введенные как CGFloat представьте подобную проблему, так как «f» кодирующий тип спецификатор относится к float, нет CGFloat. обходное решение для этого совпадает с для NSInteger: используйте локальную переменную float переменная для хранения промежуточного значения, которое Вы тогда присваиваете CGFloat переменная экземпляра.

Какао изменяет большинство перечислений для основываний NSInteger введите, который необходимо, вероятно, сделать в собственном коде также. Тем не менее, для архивации старого стиля Вас должен заархивировать enum константы на основе того, каков явный или базовый тип.

Избегайте использования @encode директива компилятора в архивации старого стиля. @encode директива генерирует символьную строку с определяемым пользователем снятым типом. Например, во время сборки LP64 NSInteger решения к long, но во время 32-разрядной сборки NSInteger решения к int. NSInteger семантика была потеряна, и это могло привести к ошибкам.

Посмотрите Проверку Кодирования для получения информации о сценарии, который можно выполнить для проверки непротиворечивости кода архивации старого стиля.

Включенная архивация

Действие сценария: Преобразовывает encodeInt:forKey: с encodeInteger:forKey: (NSInteger) и encodeFloat:forKey: с encodeDouble:forKey: (CGFloat).

Необходимо исследовать замены, сделанные сценарием видеть, могли ли бы какие-либо декодируемые значения быть вне диапазона. С включенной архивацией действительно не имеет значения при кодировании целых чисел с encodeInt:forKey:, encodeInt32:forKey:, или encodeInt64:forKey:. Но, если на декодировании, заархивированное значение больше, чем, что 32-разрядные целые числа со знаком могут содержать, NSRangeException повышен.

Для большинства интегральных значений, использования encodeInteger:forKey: и decodeIntegerForKey: рекомендуются. Для значений, диапазоны которых больше, чем, что 32-разрядные целые числа со знаком могут содержать, encodeInt64:forKey: и decodeInt64ForKey: более надлежащий выбор, даже в 32-разрядных системах.

В редком случае, где приложение хочет считать 64-разрядные значения в 32-разрядных процессах, оно может использовать decodeInt64ForKey: и будьте явными о типе вместо использования decodeIntegerForKey: (который читает назад 32-разрядный в 32-разрядных системах).

Архивация переменных со значениями NSNotFound

Действие сценария: Ни один.

NSNotFound установлен в LONG_MAX в NSObjCRuntime.h, который имеет различные значения на 32-разрядном и 64-разрядном. Следовательно, переменная, заархивированная с NSNotFound значение в 32-разрядной системе имело бы различное значение, если разархивировано в 64-разрядной системе. В свете этого удалите выписывающий код NSNotFound к архивам. Если это уже выписано, то необходимо проверить 32-разрядное значение явно при чтении его в, даже в 64-разрядном приложении.

Переменные экземпляра

Действие сценария: Преобразовывает переменные экземпляра, объявленные как int и unsigned int к NSInteger и NSUInteger, соответственно. Если целые числа объявляются меньшие, чем int и unsigned int (char или short), сценарий оставляет их в покое. Также изменения float переменные экземпляра к CGFloat если они соответствуют торгующим программируемым интерфейсам CGFloat значения.

Необходимо пробежаться через измененные переменные экземпляра и проверить, должен ли каждый быть NSInteger или NSUInteger. В некоторых случаях не могло бы быть необходимо увеличить размер переменных экземпляра, потому что, даже если программируемый интерфейс 64-разрядный способный, хранение не должно быть. Если это так, возвратите тип переменной экземпляра к int или unsigned int.

Оператор sizeof и @encode Директива

Действие сценария: Преобразовывает экземпляры sizeof и @encode где параметр int, unsigned int, и floatNSInteger, NSUInteger, и CGFloat, соответственно). Для других случаев, генерирует предупреждения (с возможными ложными отрицаниями).

Пробегитесь через каждое предупреждение и удостоверьтесь, что никакому преобразованию не нужно к сделанному вручную.

Функции, округляющие значения с плавающей точкой

Действие сценария: Преобразовывает вызовы функций такой как roundf и ceilf к (несуществующим) функциям формы _CGFloatRound.

Поскольку эти функции берут float параметры, любые вызовы к ним с CGFloat параметры должны быть обновлены. Импортируйте tgmath.h заголовок и вызов round вместо этого.

Массивы целых чисел

Действие сценария: Преобразовывает экземпляры int[] и unsigned int[] к NSInteger[] и NSUInteger[]. соответственно.

Если Вы имеете static или static const массивы int или unsigned int, и массивы не представлены в API, Вы могли бы хотеть возвратить тип для сбережений памяти.

Использование длинных и без знака долго

Действие сценария: Знаки каждое возникновение с предупреждением; не преобразовывает.

Часто отъезд нетронутого типа является надлежащим, но в некоторых случаях можно хотеть изменить его на int оставаться 32-разрядным.

Броски указателя

Действие сценария: Генерирует предупреждения для включающих бросков указателя int или float значения.

Предельные константы

Действие сценария: Генерирует предупреждения для случаев INT_MAX, INT_MIN, UINT_MAX, FLT_MAX, и FLT_MIN так как они могли бы быть вовлечены во включение сравнений long или float значения.

Переключатель (соответственно) к NSIntegerMax, NSIntegerMin, NSUIntegerMax, или надлежащее LONG_ или DBL_ варианты.

Кодирование проверки

Как дальнейший шаг к обеспечению 64-разрядного способного кода, можно выполнить сценарий, проверяющий непротиворечивость (невключенного) кода архивации старого стиля. Этот сценарий, названный CoderFormatVerifier, установлен в /Developer/Extras/64BitConversion/.

Замены сценария NSCoder вызовы метода с проверенными в типе вызовами функции. На командной строке передайте сценарий каталог — это должна быть копия Вашего исходного каталога. Сценарий рекурсивно изменяет весь .m и .M оперативные файлы и затем пишут прототипов функции в стандартный вывод (stdout). Можно тогда скопировать и вставить прототипов функции в префиксный заголовок, скомпилировать код, и затем проверить любые ошибки компилятора, которые Вы получаете. (Ошибки ссылки ожидаются, потому что сценарий только генерирует прототипов функции.) Выполненный сценарий без любых параметров за информацию об использовании.