Преобразование 32-битного приложения в 64-битное приложение на C - PullRequest
20 голосов
/ 05 января 2009

В настоящее время я работаю над преобразованием 32-битного приложения в 64-битное приложение на C. Это приложение в настоящее время работает на архитектуре x86 (Windows, osx, Unix, Linux). Поэтому, прежде чем приступить к написанию кода, я хотел знать, что мне нужно учитывать при конвертации приложения.

Ответы [ 9 ]

26 голосов
/ 05 января 2009
  1. Узнайте, кто это написал. Они идиот? Они вы несколько лет назад? Вы можете задать им вопросы? Они знакомы с существованием нескольких платформ и систем? Знание мышления автора (ов) программы поможет вам понять проблемы, когда вы столкнетесь с ними.
  2. Настройка и запуск 64-битной машины / среды сборки.
  3. Заменить long на int. Знайте, что LONG не является long.
  4. Заменить (int)&x приведение и набрав на intptr_t и (unsigned int)&x на uintptr_t
  5. Аудит всего, что полагается на приведение структур к char* для выполнения арифметики с указателями.
  6. Регулярно ищите \ <4 \>, если вы предполагаете 4 = sizeof(void*)
  7. Будьте терпеливы. Когда вы найдете проблему, посмотрите в другом месте, если такая же проблема существует, и оберните решение в макрос.
  8. Старайтесь не использовать #ifdef RUN64 или что-нибудь подобное. Вы пожалеете об этом, если 128-битные платформы когда-либо войдут в моду.
  9. Инкапсулируйте все ваши изменения с точки зрения некоторых централизованных макросов, которые скрывают различия в переносимости в других местах вашей программы.
  10. Используйте тестер покрытия, чтобы убедиться, что вы покрыли все (при необходимости)

РЕДАКТИРОВАТЬ добавлено uintptr_t примечание, как предлагается в комментарии.

8 голосов
/ 05 января 2009

Одна потенциальная проблема, которая еще не упоминалась, заключается в том, что если ваше приложение читает или записывает двоичные данные с диска (например, читает массив структур, используя fread), вам придется очень тщательно проверить и, возможно, получить считыватели: один для устаревших файлов и один для 64-битных файлов. Или, если вы осторожно используете типы, такие как uint32_t и т. Д. Из заголовочного файла <stdint.h>, вы можете переопределить свои структуры, чтобы они были побитно-совместимыми. В любом случае, двоичный ввод / вывод - вещь, на которую следует обратить внимание.

5 голосов
/ 05 января 2009

Это действительно зависит от приложения и от того, как оно было закодировано. Некоторый код можно просто перекомпилировать с помощью 64-битного компилятора, и он будет работать, но обычно это происходит только в том случае, если код был разработан с учетом переносимости.

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

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

4 голосов
/ 05 января 2009

Если вы использовали правильные типы для ваших значений - например. size_t, ptrdiff_t, uintptr_t, целочисленные типы int фиксированного размера от stdint.h, где это уместно, и значения жестких кодов не заданы, ваш код должен работать "из коробки".

3 голосов
/ 05 января 2009

Ну, в принципе, количество изменений довольно мало, но это все равно будет серьезной задачей, если приложение не будет тщательно написано, чтобы быть несколько портативным для начала.

Основное отличие состоит в том, что указатели имеют ширину 64 бита, , но большинство других типов данных не изменяются. Int по-прежнему 32-битный, а long, вероятно, также 32-битный. Так что, если ваш код преобразуется между int и указателями, это сломается. Точно так же любая структура или аналог, который зависит от определенного смещения для члена, может сломаться, потому что другие члены теперь могут быть больше, и поэтому изменить смещение.

Конечно, ваш код никогда не должен полагаться на эти уловки, поэтому в идеальном мире это не будет проблемой, и вы можете просто перекомпилировать, и все будет работать. Но вы, вероятно, не живете в идеальном мире ...;)

3 голосов
/ 05 января 2009

Основная проблема, с которой вы сталкиваетесь при переходе на 64-битную версию, состоит в том, что размер указателей различен (64-битная вместо 32-duh). Размер целых чисел и размер long также могут различаться в зависимости от платформы.

Почему это проблема? Ну, это не так, если только ваш код не предполагает, что sizeof (int) == sizeof (void *). Это может привести к неприятным ошибкам указателя.

2 голосов
/ 20 апреля 2009

Все о 64-битном для разработчиков:

Статьи о 64-битной разработке

Коллекция ссылок 64-битные ресурсы

Инструмент Viva64

2 голосов
/ 05 января 2009

Уже есть много хороших ответов.

Рассмотрите возможность использования Gimpel Lint . Он может указать именно те типы конструкций, которые являются проблематичными. Если ваш опыт похож на мой, он также покажет вам множество ошибок в системе, не связанных с 32/64 битным портом.

2 голосов
/ 05 января 2009

Два основных различия между 32-битным и 64-битным программированием в C - это sizeof (void *) и sizeof (long). Основная проблема, с которой вы столкнетесь, заключается в том, что большинство систем Unix используют стандарт I32LP64, который определяет длину до 64 бит, а Win64 использует стандарт IL32LLP64, который определяет длину до 32 бит. Если вам требуется поддержка кроссплатформенной компиляции, вы можете использовать набор архитектурных определений типов для 32-разрядных и 64-разрядных целых чисел, чтобы гарантировать, что весь код будет работать согласованно. Это предоставляется как часть stdint.h как часть стандарта C99. Если вы не используете компилятор C99, вам может потребоваться свернуть собственный эквивалент

Как отмечено в другом месте, основными проблемами для преобразования будет код, который принимает sizeof (int) == sizeof (long) == sizeof (void *), код для поддержки данных, записанных на диск, и код для межплатформенного IPC .

Для хорошего обзора истории этого взгляните на эту статью из очереди ACM.

...