Преобразование приложения к 64-разрядному двоичному файлу
На высоком уровне вот шаги для создания приложения, предназначающегося и для 32-разрядного и для 64-разрядных сред выполнения:
Установите последний XCode.
Откройте свой проект. XCode предлагает Вам модернизировать свой проект. Модернизация проекта добавляет новые предупреждения и ошибки, которые важны при компиляции приложения для 64-разрядного.
Обновите свои настройки проекта для поддержки iOS 5.1.1 или позже. Вы не можете разработать 64-разрядный проект, если он предназначается для версии iOS ранее, чем iOS 5.1.
Измените настройки сборки Архитектуры в своем проекте к “Стандартной Архитектуре (включая 64-разрядный)”.
Обновите свое приложение для поддержки 64-разрядной среды выполнения. Новые предупреждения компилятора и ошибки помогут вести Вас посредством этого процесса. Однако компилятор не выполняет всю работу для Вас; используйте информацию в этом документе, чтобы помочь вести Вас посредством исследования Вашего собственного кода.
Протестируйте свое приложение на фактических 64-разрядных аппаратных средствах. Средство моделирования iOS может также быть полезным во время разработки, но некоторых изменений, таким как функциональные соглашения о вызовах, видимы только, когда Ваше приложение работает на устройстве.
Используйте Инструменты для настройки производительности памяти приложения.
Представьте приложение, включающее обе архитектуры для утверждения.
Остаток от этой главы описывает проблемы, часто происходящие при портировании Сенсорного приложения Какао на 64-разрядную среду выполнения. Используйте эти разделы для руководства собственных усилий исследовать код.
Не бросайте указатели на целые числа
Существует немного причин бросить указатели на целый тип. Путем непротиворечивого использования типов указателей Вы гарантируете, что все Ваши переменные измерены достаточно большие для содержания адреса.
Например, код в Перечислении 2-1 бросает указатель на int
введите, потому что это хочет выполнить арифметику на адресе. В 32-разрядное время выполнения этот код работает потому что int
введите и указатель тот же размер. Однако в 64-разрядное время выполнения, указатель больше, чем int
введите, таким образом, присвоение теряет некоторые данные указателя. Здесь, потому что указатель совершенствуется его собственным размером, можно просто постепенно увеличить указатель.
Перечисление 2-1 Бросая указатель на int
int *c = something passed in as an argument.... |
int *d = (int *)((int)c + 4); // Incorrect. |
int *d = c + 1; // Correct! |
Если необходимо преобразовать указатель на целый тип, всегда используйте uintptr_t
введите для предотвращения усечения. Обратите внимание на то, что изменение значений указателя через целочисленную математику и затем преобразование его назад в указатель может нарушить правила искажения основного типа. Когда к неправильно выровненному указателю получают доступ, это может привести к неожиданному поведению от компилятора, а также отказов процессора.
Используйте типы данных последовательно
Когда Вы последовательно не используете типы данных всюду по Вашему коду, заканчиваются много общих программных ошибок. Даже при том, что компилятор предупреждает Вас относительно многих проблем, следующих из использования типа данных противоречиво, также полезно видеть несколько изменений этих образцов так, чтобы можно было распознать их в коде.
При вызывании функции всегда соответствуйте переменную, получающую результаты к типу возврата функции. Если тип возврата является большим целым числом, чем переменная получения, значение является усеченным. Перечисление 2-2 показывает простой образец, показывающий эту проблему. PerformCalculation
функционируйте возвращает a long
целое число. В 32-разрядное время выполнения, обоих int
и long
32 бита, таким образом, присвоение на int
введите работы, даже при том, что код является неправильным. Когда присвоение сделано, в 64-разрядное время выполнения потеряны верхние 32 бита результата. Вместо этого результат должен быть присвоен a long
целое число; этот подход последовательно работает в оба времени выполнения.
Усечение перечисления 2-2 при присвоении возвращаемого значения переменной
long PerformCalculation(void); |
int x = PerformCalculation(); // incorrect |
long y = PerformCalculation(); // correct! |
Когда Вы передаете в значении в качестве параметра, та же проблема происходит. Например, в Перечислении 2-3 входной параметр является усеченным, когда выполняется в 64-разрядное время выполнения.
Усечение перечисления 2-3 входного параметра
int PerformAnotherCalculation(int input); |
long i = LONG_MAX; |
int x = PerformCalculation(i); |
В Перечислении 2-4 возвращаемое значение является также усеченным в 64-разрядное время выполнения, потому что значение возвратилось, превышает диапазон типа возврата функции.
Усечение перечисления 2-4 при возврате значения
int ReturnMax() |
{ |
return LONG_MAX; |
} |
Все эти примеры следуют из кода, принимающего это int
и long
идентичны. ANSI C стандарт не делает это предположение, и это явно неправильно при работе в 64-разрядное время выполнения. По умолчанию, если Вы модернизировали свой проект, -Wshorten-64-to-32
параметр компилятора был автоматически включен, таким образом, компилятор автоматически предупреждает Вас о многих случаях, где значение является усеченным. Если бы Вы не модернизировали свой проект, то необходимо явно включить тот параметр компилятора. Дополнительно, можно хотеть включать -Wconversion
опция, которая более многословна, но находит более потенциальные ошибки.
В Сенсорном приложении Какао ищите следующие целые типы и удостоверьтесь, что Вы используете их правильно:
long
NSInteger
CFIndex
size_t
(результат вызоваsizeof
внутренняя работа)
И в обеих средах выполнения, fpos_t
и off_t
типы составляют 64 бита в размере, поэтому никогда не присваивают их int
ввести.
Перечисления также вводятся
В компиляторе LLVM перечислимые типы могут определить размер перечисления. Это означает, что некоторые перечислимые типы могут также иметь размер, который больше, чем Вы ожидаете. Решение, как во всех других случаях, не состоит в том, чтобы сделать предположения о размере типа данных. Вместо этого присвойте любые перечисляемые значения переменной с надлежащим типом данных.
Общие проблемы преобразования типов в касании какао
Касание какао, особенно Базовая Основа и Основа, добавляют дополнительные ситуации для поиска, потому что они предлагают способы сериализировать тип данных C или получить его в объекте Objective C.
NSInteger изменяет размер в 64-разрядном коде. NSInteger
тип используется всюду по Касанию Какао; это - 32-разрядное целое число в 32-разрядное время выполнения и 64-разрядное целое число в 64-разрядное время выполнения. Таким образом, при получении информации из метода платформы, берущего NSInteger
введите, используйте NSInteger
введите для содержания результата.
Несмотря на то, что Вы никогда не должны делать предположение что NSInteger
тип является тем же размером как int
введите, вот несколько критических примеров для поиска:
Преобразование в или от
NSNumber
объект.Кодирование и декодирование данных с помощью
NSCoder
класс. В частности если Вы кодируетеNSInteger
на 64-разрядном устройстве и позже декодируют его на 32-разрядном устройстве, метод декодирования выдает исключение, если значение превышает диапазон 32-разрядного целого числа. Можно хотеть использовать явный целый тип вместо этого (см. Использование Явные Целочисленные типы данных).Работа с константами, определенными в платформе как
NSInteger
. Особо значимыйNSNotFound
постоянный. В 64-разрядное время выполнения его значение больше, чем максимальный диапазонint
введите, таким образом усечение его значения часто вызывает ошибки в Вашем приложении.
CGFloat изменяет размер в 64-разрядном коде. CGFloat
введите изменения в 64-разрядном числе с плавающей точкой. Как с NSInteger
введите, Вы не можете принять это CGFloat
a float
или a double
. Так использование CGFloat
последовательно. Перечисление 2-5 показывает пример что Основа Ядра использования для создания a CFNumber
. Но код принимает это a CGFloat
тот же размер как a float
, который является неправильным.
Использование перечисления 2-5 CGFloat
типы последовательно
// Incorrect. |
CGFloat value = 200.0; |
CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &value); |
// Correct! |
CGFloat value = 200.0; |
CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &value); |
Будьте осторожны при выполнении целочисленных вычислений
Несмотря на то, что усечение является наиболее распространенной проблемой, можно также столкнуться с другими проблемами, связанными с целочисленным изменением. Этот раздел включает некоторое дополнительное разъяснение, которое можно использовать для обновления кода.
Правила расширения знака для C и языков C-derived
C и подобные языки используют ряд правил расширения знака определить, обработать ли главный бит в целом числе как знаковый бит, когда значение присваивается переменной большей ширины. Правила расширения знака следующие:
Значения без знака являются расширенным нулем (не, подписываются расширенный), когда продвинуто на больший тип.
Даже если получающийся тип без знака, значения со знаком всегда являются знаком, расширенным, когда продвинуто на больший тип.
Константы (если не изменено суффиксом, такой как
0x8L
) обрабатываются как самый маленький размер, который будет содержать значение. Числа, записанные в шестнадцатеричном, могут быть обработаны компилятором какint
,long
, иlong long
типы и могут быть такжеsigned
илиunsigned
типы. Десятичные числа всегда обрабатываются какsigned
типы.Сумма значения со знаком и значения без знака того же размера является значением без знака.
Перечисление 2-6 показывает пример неожиданного поведения, следующего из этих правил вместе с сопроводительным объяснением.
Пример Расширения знака перечисления 2-6 1
int a=-2; |
unsigned int b=1; |
long c = a + b; |
long long d=c; // to get a consistent size for printing. |
printf("%lld\n", d); |
Проблема: Когда этот код выполняется в 32-разрядное время выполнения, результат -1
(0xffffffff
). Когда код выполняется в 64-разрядное время выполнения, результат 4294967295
(0x00000000ffffffff
), который является, вероятно, не, что Вы ожидали.
Причина: Почему это происходит? Во-первых, эти два числа добавляются. Значение со знаком плюс значение без знака приводит к значению без знака (правило 4). Затем, то значение продвинуто на больший тип. Это продвижение не вызывает расширение знака.
Решение: Для решения этой проблемы совместимым способом на 32 бита бросить b
к a long
целое число. Этот бросок вызывает не, подписывают расширенное продвижение b
к 64-разрядному типу до дополнения, таким образом вынуждая целое число со знаком быть продвинутым (способом со знаком) для соответствия. С тем изменением результатом является ожидаемый -1
.
Перечисление 2-7 показывает связанный пример с сопроводительным объяснением.
Пример Расширения знака перечисления 2-7 2
unsigned short a=1; |
unsigned long b = (a << 31); |
unsigned long long c=b; |
printf("%llx\n", c); |
Проблема: ожидаемый результат (и результат 32-разрядной исполнимой программы) 0x80000000
. Результат, сгенерированный 64-разрядной исполнимой программой, однако, 0xffffffff80000000
.
Причина: Почему расширяется этот знак? Во-первых, когда оператор сдвига вызывается, переменная a
продвинут на переменную типа int
. Поскольку все значения a short
целое число может вписаться в со знаком int
введите, результат этого продвижения подписывается.
Во-вторых, когда сдвиг завершился, результат был сохранен в a long
целое число. Таким образом, 32-разрядное значение со знаком, представленное (a << 31)
был знак, расширенный (правило 2), когда это было продвинуто на 64-разрядное значение (даже при том, что получающийся тип без знака).
Решение: Бросьте начальное значение к a long
целое число до сдвига. Короткое продвинуто только один раз — на сей раз к 64-разрядному типу (по крайней мере, когда скомпилировано как 64-разрядная исполнимая программа).
Работа с битами и битовыми масками
При работе с битами и масках с 64-разрядными значениями, Вы хотите избежать получать 32-разрядные значения непреднамеренно. Вот некоторые подсказки для помощи Вам.
Не предполагайте, что тип данных имеет определенную длину. Если Вы смещаетесь через биты, сохраненные в переменной типа long
целое число, используйте LONG_BIT
значение для определения числа битов в a long
целое число. Результат сдвига, превышающего длину переменной, является архитектурно-зависимым.
Используйте инвертированные маски в случае необходимости. Будьте осторожны при использовании битовых масок с long
целые числа, потому что ширина отличается между 32-разрядными и 64-разрядными временами выполнения. Существует два способа создать маску, в зависимости от того, хотите ли Вы, чтобы маска была расширенным нулем или один расширенный:
Если Вы хотите, чтобы значение маски содержало нули в верхних 32 битах в 64-разрядное время выполнения, обычные фотошаблоны фиксированной ширины как ожидалось, потому что это будет расширено способом без знака на 64-разрядное количество.
Если Вы хотите, чтобы значение маски содержало в верхних битах, запишите маску как поразрядную инверсию ее инверсии, как показано в Перечислении 2-8.
Перечисление 2-8 Используя инвертированную маску для расширения знака
function_name(long value) |
{ |
long mask = ~0x3; // 0xfffffffc or 0xfffffffffffffffc |
return (value & mask); |
} |
В коде обратите внимание на то, что верхние биты в маске заполнены в 64-разрядном случае.
Создайте структуры данных с фиксированным размером и выравниванием
Когда данные совместно используются 32-разрядными и 64-разрядными версиями Вашего приложения, Вы, возможно, должны создать структуры данных, 32-разрядные и 64-разрядные представления которых идентичны, главным образом когда данные хранятся к файлу или передаются через сеть к устройству, которое может иметь противоположную среду выполнения. Но также и имейте в виду, что пользователь мог бы скопировать их данные, хранившие на 32-разрядном устройстве, и затем восстановить те данные к 64-разрядному устройству. Таким образом, функциональная совместимость данных является проблемой, которую необходимо решить.
Используйте явные целочисленные типы данных
Стандарт C99 обеспечивает встроенные типы данных, которые, как гарантируют, будут определенным размером, независимо от архитектуры используемого оборудования. Необходимо использовать эти типы данных, когда данные должны быть фиксированным размером или когда Вы знаете, что определенная переменная имеет ограниченный диапазон возможных значений. Путем выбора надлежащего типа данных Вы получаете тип фиксированной ширины, который можно сохранить в памяти, и Вы также избегаете тратить впустую память путем выделения переменной, диапазон которой намного больше, чем Вам нужно.
Таблица 2-1 перечисляет типы C99 вместе с диапазонами позволенных значений для каждого.
Ввести | Диапазон |
---|---|
int8_t | - От 128 до 127 |
int16_t | - От 32,768 до 32 767 |
int32_t | - 2,147,483,648 - 2 147 483 647 |
int64_t | - 9,223,372,036,854,775,808 к 9,223,372,036,854,775,807 |
uint8_t | От 0 до 255 |
uint16_t | От 0 до 65 535 |
uint32_t | От 0 до 4,294,967,295 |
uint64_t | От 0 до 18,446,744,073,709,551,615 |
Будьте Осторожны При Выравнивании 64-разрядных Целых типов
В 64-разрядное время выполнения выравнивание всех 64-разрядных целых типов изменяется с 4 байтов до 8 байтов. Даже при указании каждого целого типа явно эти две структуры все еще могут не быть идентичными в оба времени выполнения. В Перечислении 2-9 изменяется выравнивание даже при том, что поля объявляются с явными целыми типами.
Выравнивание перечисления 2-9 64-разрядных целых чисел в структурах
struct bar { |
int32_t foo0; |
int32_t foo1; |
int32_t foo2; |
int64_t bar; |
}; |
Когда этот код компилируется с 32-разрядным компилятором, полем bar
начинает 12 байтов с запуска структуры. Когда тот же код компилируется с 64-разрядным компилятором, полем bar
начинает 16 байтов с запуска структуры. Четыре байта дополнения добавляются после foo2
так, чтобы bar
выровненный к 8-байтовой границе.
Если Вы определяете новую структуру данных, организуете элементы с самыми большими значениями выравнивания сначала и самые маленькие элементы в последний раз. Эта организация структуры избавляет от необходимости большинство дополнительных байтов. Если Вы работаете с существующей структурой, включающей неправильно выровненные 64-разрядные целые числа, можно использовать прагму для принуждения надлежащего выравнивания. Перечисление 2-10 показывает ту же структуру данных, но здесь структура вынуждена использовать 32-разрядные правила выравнивания.
Перечисление 2-10 Используя прагмы для управления выравниванием
#pragma pack(4) |
struct bar { |
int32_t foo0; |
int32_t foo1; |
int32_t foo2; |
int64_t bar; |
}; |
#pragma options align=reset |
Используйте эту опцию только при необходимости, потому что существует потеря производительности для неправильно выровненных доступов. Например, Вы могли бы использовать эту опцию поддержать обратную совместимость со структурами данных уже в использовании в 32-разрядной версии Вашего приложения.
Выделите Память Используя sizeof
Никогда не вызывайте malloc
с явным размером (например, malloc(4)
) выделять площадь для переменной. Всегда используйте sizeof
для получения корректного размера для любой структуры или переменной, Вы выделяете. Ищите свой код любой экземпляр malloc
это не сопровождается sizeof
.
Обновите строки формата для поддержки обоих времен выполнения
Печать функционирует такой как printf
когда Вы пишете код для поддержки обоих времен выполнения из-за изменений типа данных, может быть хитрым. Решить эту проблему для целых чисел размера указателя (uintptr_t
) и другие стандартные типы, используйте различные макросы, определенные в inttypes.h
заголовочный файл.
Строки формата для различных типов данных описаны в Таблице 2-2. Эти дополнительные типы, перечисленные в inttypes.h
заголовочный файл, описаны в Таблице 2-3.
Ввести | Строка формата |
---|---|
|
|
|
|
|
|
|
|
|
|
любой указатель |
|
Ввести | Строка формата |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Например, для печати intptr_t
переменная (целое число размера указателя) и указатель, Вы пишете код, подобный этому в Перечислении 2-11.
Перечисление 2-11 Архитектурно-независимая печать
#include <inttypes.h> |
void *foo; |
intptr_t k = (intptr_t) foo; |
void *ptr = &k; |
printf("The value of k is %" PRIdPTR "\n", k); |
printf("The value of ptr is %p\n", ptr); |
Заботьтесь с функциями и указателями функции
Вызовы функции в 64-разрядное время выполнения обрабатываются по-другому, чем функции в 32-разрядное время выполнения. Критическое различие - то, что вызовы функции с прототипами variadic используют различную последовательность инструкций для чтения их параметров, чем функции, берущие фиксированный список параметров. Перечисление 2-12 показывает прототипы для двух функций. Первая функция (fixedFunction
) всегда берет пару целых чисел. Вторая функция берет переменное число параметров (но по крайней мере два). В 32-разрядное время выполнения оба из вызовов функции в Перечислении 2-12 используют подобную последовательность инструкций для чтения данных параметра. В 64-разрядное время выполнения две функции компилируются с помощью абсолютно отличающихся соглашений.
Перечисление 2-12 64-разрядные соглашения о вызовах варьируется функциональным типом
int fixedFunction(int a, int b); |
int variadicFunction(int a, ...); |
int main |
{ |
int value2 = fixedFunction(5,5); |
int value1 = variadicFunction(5,5); |
} |
Поскольку соглашения о вызовах намного более точны в 64-разрядное время выполнения, необходимо удостовериться, что функция всегда вызывается правильно, так, чтобы вызываемый всегда нашел параметры, которые обеспечила вызывающая сторона.
Всегда определяйте прототипов функции
При компиляции использования модернизированных настроек проекта компилятор генерирует ошибки, при попытке сделать вызов функции к функции, не имеющей явного прототипа. Необходимо обеспечить прототипа функции так, чтобы компилятор мог определить, является ли функция функцией variadic или нет.
Указатели функции должны использовать корректный прототип
При передаче указателя функции в коде его соглашения о вызовах должны остаться непротиворечивыми. Это должно всегда брать тот же набор параметров. Никогда не бросайте функцию variadic к функции, берущей постоянное число параметров (или наоборот). Перечисление 2-13 является примером проблематичного вызова функции части. Поскольку указатель функции был брошен для использования различного набора соглашений о вызовах, вызывающая сторона собирается поместить параметры в место, которое не ожидает вызванная функция. Это несоответствие может заставить Ваше приложение разрушать или показывать другие непредсказуемые способы поведения.
Кастинг перечисления 2-13 между variadic и nonvariadic функционирует результаты по ошибке
int MyFunction(int a, int b, ...); |
int (*action)(int, int, int) = (int (*)(int, int, int)) MyFunction; |
action(1,2,3); // Error! |
Сообщения Objective C отгрузки Используя прототип функции метода
Когда Вы вызываете, исключение к правилу кастинга, описанному выше, - objc_msgSend
функционируйте или любые другие подобные функции во время выполнения Objective C, отправляющие сообщения. Несмотря на то, что прототип для функций сообщения имеет форму variadic, функция метода, вызванная временем выполнения Objective C, не совместно использует тот же прототип. Время выполнения Objective C непосредственно диспетчеризирует функции, реализующей метод, таким образом, соглашениям о вызовах не соответствуют, как описано ранее. Поэтому необходимо бросить objc_msgSend
функционируйте к прототипу, соответствующему вызванную функцию метода.
Перечисление 2-14 показывает надлежащую форму для диспетчеризации сообщения к объекту с помощью низкоуровневых функций сообщения. В этом примере, doSomething:
метод берет единственный параметр и не имеет формы variadic. Это бросает objc_msgSend
функция с помощью прототипа функции метода. Обратите внимание на то, что функция метода всегда берет id
переменная и селектор как его первые два параметра. После objc_msgSend
функция брошена к указателю функции, вызов диспетчеризируется через тот же самый указатель функции.
Перечисление 2-14 Используя бросок для вызывания сообщения Objective C, отправляющего функции
- (int) doSomething:(int) x { ... } |
- (void) doSomethingElse { |
int (*action)(id, SEL, int) = (int (*)(id, SEL, int)) objc_msgSend; |
action(self, @selector(doSomething:), 0); |
} |
Будьте осторожны при вызывании функций Variadic
Списки аргумента переменной (varargs
) не предоставляйте информацию типа для параметров, и параметры автоматически не продвинуты на большие типы. Если необходимо различить различные входные типы данных, Вы, как ожидают, будете использовать строку формата или другой подобный механизм для предоставления той информации varargs
функция. Если функция вызова правильно не предоставляет ту информацию (или если varargs
функция не интерпретирует его правильно), Вы получаете неправильные результаты.
В частности если Ваш varargs
функция ожидает a long
целое число и Вы передаете в 32-разрядном значении, varargs
функция содержит 32 бита данных и 32 бита мусора от следующего параметра (который Вы теряете в результате). Аналогично, если Ваш varargs
функция ожидает int
введите и Вы передаете в a long
целое число, Вы получаете только половину данных, и остальное неправильно появляется в следующем параметре. (Один пример этого происходит при использовании неправильного printf
строки формата.)
Никогда не получайте доступ к указателю Objective C непосредственно
Если у Вас есть код, непосредственно получающий доступ к объекту isa
поле, тот код перестал работать при выполнении в 64-разрядное время выполнения. isa
поле больше не содержит указатель. Вместо этого это включает некоторые данные указателя и использует остающиеся биты для содержания другой информации о выполнении. Эта оптимизация улучшает и использование памяти и производительность.
Считать объект isa
поле, используйте class
свойство или вызов object_getClass
функция вместо этого. Записать в объект isa
поле, вызовите object_setClass
.
Используйте встроенные примитивы синхронизации
Иногда, приложения реализуют свои собственные примитивы синхронизации для улучшения производительности. Среда выполнения iOS обеспечивает полное дополнение примитивов, оптимизированных и исправляющих для каждого CPU, на котором они работают. Эта библиотека времени выполнения обновляется, поскольку добавляются новые архитектурные опции. Существующие 32-разрядные приложения, полагающиеся на библиотеку времени выполнения автоматически, используют в своих интересах новые функции CPU, представленные в 64-разрядном мире. При реализации пользовательских примитивов в предыдущей версии приложения теперь Вы могли бы полагаться на инструкции или пути, которые являются порядками величины медленнее, чем встроенные примитивы. Вместо этого всегда используйте встроенные примитивы.
Никогда Твердый Код размер страницы виртуальной памяти
Большинство приложений не должно знать размер страницы виртуальной памяти, но некоторое использование это для распределений буферов и некоторых вызовов платформы. Начиная с iOS 7 размер страницы может варьироваться между устройствами и в 32-разрядные и в 64-разрядные времена выполнения. Поэтому всегда используйте getpagesize()
функция для получения размера страницы.
Пойдите независимая позиция
64-разрядная среда выполнения поддерживает только Position-Independent Executables (PIE). Самыми современными приложениями по умолчанию создаются как независимая позиция. Если у Вас есть что-то, что препятствует тому, чтобы Ваше приложение создало как позиция независимый код, такой как статически соединенная библиотека или ассемблерный код, необходимо обновить этот код при портировании приложения на 64-разрядное время выполнения. Независимость позиции также настоятельно рекомендована для 32-разрядных приложений.
Для получения дополнительной информации посмотрите Создание Позиции Независимая Исполнимая программа.
Сделайте свое выполнение приложения хорошо в 32-разрядное время выполнения
В настоящее время приложение, записанное для 64-разрядной среды выполнения, должно также поддерживать 32-разрядное время выполнения. Таким образом, необходимо сделать приложения, работающие хорошо при выполнении в любой среде. Обычно это означает создавать единственный проект, работающий хорошо в обеих средах. Иногда, Вы, возможно, должны разработать определенные решения для каждой среды выполнения.
Например, Вы могли бы испытать желание использовать 64-разрядные целые числа всюду по своему коду; обе среды поддерживают 64-разрядные целые типы, и использование только единственного целого типа везде упрощает проект Вашего приложения. При использовании 64-разрядных целых чисел везде приложение будет работать более медленно в 32-разрядное время выполнения. 64-разрядный процессор может выполнить 64-разрядные целочисленные операции так же быстро как 32-разрядные целочисленные операции, но 32-разрядный процессор выполняет 64-разрядные вычисления намного более медленно. И в обеих средах, переменная может использовать больше памяти, чем необходимо. Вместо этого переменная должна использовать целый тип, соответствующий диапазон значений, которые Вы ожидаете, что он будет содержать. Если вычисление всегда помещается в 32-разрядное целое число, используйте 32-разрядное целое число. Посмотрите Использование Явные Целочисленные типы данных.