Что следует учитывать при написании кода, переносимого как на 32-, так и на 64-битную архитектуру
-
20-09-2019 - |
Вопрос
Какие моменты следует учитывать при написании кода, который должен быть переносимым как на 32-битные, так и на 64-битные машины?
Размышляя об этом подробнее, я считаю, что если бы вы могли поделиться своим опытом с точки зрения возникающих проблем, это помогло бы.
Добавляя к этому, однажды я столкнулся с проблемой из-за отсутствия прототипа функции, которая возвращала указатель.Когда я портировал то же самое на 64-битную машину, код давал сбой, и я долгое время понятия не имел о причине, позже понял, что предполагается, что все отсутствующие прототипы возвращают int, вызывая проблему.
Любые подобные примеры могут помочь.
РЕДАКТИРОВАТЬ:Добавление в вики сообщества.
Решение
Ошибки:
- Приведение указателей к целочисленным типам опасно
- Размеры структуры данных могут меняться
- Следите за расширением знака
- Другой ABI?
Некоторые советы и рекомендации, которые я нашел полезными:
- Получите целочисленный тип собственного размера (из заголовка или
typedef
свой собственный) и используйте его, когда у вас есть переменные, для которых размер не важен. - Используйте явные типы переменных везде, где это возможно (u_int64_t, int_32_t и т. д.).
Другие советы
- Некоторые цельные типы могут иметь разные размеры.
- Указатели имеют разную длину.
- Заполнение структуры
- Выравнивание
В Windows существует только соглашение о вызовах на x64, а не на обычном компьютере x32.
Ситуация становится еще более мрачной, если у вас есть 32-битные и некоторые 64-битные компоненты.В Windows я написал COM-сервис, чтобы заставить их общаться.
Помещение указателей в стек занимает вдвое больше места.Однако размер стека может не меняться в зависимости от версии ОС, в результате чего код, который нормально работает в 32-разрядной версии, загадочным образом дает сбой при компиляции и запуске без изменений в 64-разрядной версии.Не спрашивайте меня, откуда я это знаю.
sizeof(int) может != sizeof(void*)
выравнивание.Вполне возможно, что потребности в выравнивании могут измениться.Это может выявить ошибки, когда вы неправильно обращались с вещами, которые должны были быть выровнены, но были выровнены только случайно в 32-битной версии (или на процессоре, которому все равно).
не передавайте 0 в переменные аргументы, если получатель ожидает указатель.Это болезненно для C++, где опытные разработчики знают, что 0 — допустимый нулевой указатель.Разработчик C обычно использует NULL, так что вы, вероятно, в порядке.
Пишите автоматические тесты и регулярно запускайте их на обеих платформах.