How to make sure that my program will be fully portable?
Это необходимое, но не достаточное условие для правильного выполнения каких-либо действий. Для проверки переносимости вам понадобится несколько платформ и компиляторов.
Это означает, что делайте что-то только в том случае, если в стандарте указано, что вы можете это сделать. Ожидайте определенного результата только в том случае, если стандарт гласит, что его можно ожидать. Используйте только библиотеку или API, если в стандарте указано, что они существуют. Стандарт доступен здесь (среди прочего):
http://openassist.googlecode.com/files/C%2B%2B%20Standard%20-%20ANSI%20ISO%20IEC%2014882%202003.pdf
Это поможет, если вы предположите, что:
int
- это 37-битный тип. Или 16-битный тип. time_t
is double
И так далее. Под этим я не имею в виду написание кода, который полагается на эти вещи как истинные, я имею в виду написание кода, который будет работать, если они есть, а также будет работать над разумной реализацией.
. Это единственный практический способ дать себе разумные шансы на достижение (1).
Теоретически нет ничего непереносимого в программе на C ++, которая использует экспорт
. Если это совершенно хорошая программа на C ++ во всех остальных отношениях, то она будет работать с любым совместимым компилятором C ++. Но вряд ли кто-то использует соответствующий компилятор C ++, поэтому существует де-факто общее подмножество C ++, которого вы захотите придерживаться.
. Некоторые вещи не переносятся в стандартном C ++, например рисование графики на экране, поскольку в стандартном C ++ нет графики или GUI API. Так что не существует такой вещи, как «полностью переносимая» программа с графическим интерфейсом пользователя, написанная на C ++. Таким образом, вам может потребоваться или нет пересмотреть свою цель, в зависимости от того, что должна делать ваша программа.
Если вашей программе требуется что-то, что просто невозможно сделать полностью в рамках стандартного C ++, вы можете упростить перенос своей программы, инкапсулируя это поведение в интерфейсе, который, по вашему мнению, должен быть реализован на всех платформах, которые вам нужны. Затем приступайте к реализации его для каждого из них. Однако это не приводит к «полностью переносимой» программе, поскольку для меня это означает программу, которую вы можете скомпилировать и запустить без изменений в любой соответствующей реализации C ++. Программа, которая может быть перенесена на большинство платформ с помощью компилятора C ++, вероятно, при условии, что у них есть экран и мышь, с некоторой специальной работой по программированию, - это не одно и то же.
Все это, конечно, можно зайти слишком далеко.Вы, вероятно, действительно захотите предположить, что CHAR_BIT
равно 8 (в противном случае чтение файлов - безумие), и, возможно, даже положитесь на структуру GUI, такую как Qt. Но вы сказали «полностью переносимый», и одна из основных вещей, которые вам нужно сделать для написания переносимых программ, - это обычно определить, насколько далеко вы готовы пойти на «полный» компромисс.
Во время компиляции, если вы можете, или во время выполнения в противном случае, убедитесь, что если ваша программа требует, чтобы int был не менее 32 бит (или что-то еще), тогда она с шумом выйдет из строя, когда это не так. Хорошо, поэтому комплексное тестовое покрытие могло бы выявить случаи, когда ваша арифметика молча выходит за пределы и дает неправильный ответ, но сложно написать действительно всеобъемлющие тесты, и в любом случае тесты могут давать те же непереносимые ошибки, что и код, или какой-нибудь плохой лох, который загрузил ваш код, возможно, они не все запускаются должным образом.
Когда вы используете библиотеки, вы фактически делаете это автоматически. Вы #include
какой-нибудь заголовок, и если библиотека недоступна, это сразу же завершится ошибкой. По крайней мере, вы надеетесь, что это будет - вполне возможно, что какая-то другая реализация может иметь заголовок с тем же именем, который делает что-то радикально или тонко отличное. Радикальные различия обычно приводят к сбоям компиляции, на наличие тонких различий вы можете проверить символы препроцессора , чтобы идентифицировать реализации .
Избегайте библиотек, специфичных для конкретной платформы.
Разрабатывайте в наиболее ограничительной среде компиляции. Используйте наименьший набор функций из C++. Разделите платформозависимые части кода на отдельные файлы. Разработайте среду конфигурации (make) для каждой платформы, как часть программного пакета.
На ваш вопрос:
Как убедиться, что моя программа будет полностью переносимой? На
нельзя дать удовлетворительный ответ. Вы не можете ни в одном реальном приложении убедиться, что оно переносимо. Вы можете подтвердить свои ожидания только путем точных тестов приложения на целевой платформе, как это уже было предложено здесь Лу Франко .
В процессе разработки и параллельного тестирования на разных платформах или средах каждый из нас находит свой набор уловок и исследует свою долю ловушек. В одном комментарии вы сказали, что работаете в системе Windows. Это хорошо. Попробуйте заставить вашу программу работать с компилятором Visual Studio (и средой).Затем установите CygWin с набором компиляторов GCC 4.x . Установите среду IDE Netbeans и среду C ++ и создайте проект на основе тех же исходных кодов. Netbeans будет использовать Cygwin GCC 4.x. Если ваша скомпилированная программа работает с обеими цепочками инструментов, вы, вероятно, преодолели около 90% реальных препятствий, связанных с переносимостью.
С уважением
rbo
Хорошим началом было бы использование только тех библиотек, которые действительно существуют на всех целевых платформах.
Обеспечение соответствия стандартам. По крайней мере, общее подмножество стандарта, которое реализуется поставщиками на всех платформах, на которых вы собираетесь развернуть свое приложение.
Отделите специфичные для платформы части от платформенно-независимых. Как правило, нижний или два слоя должны иметь дело с платформой.
Будьте в курсе изменений:
Тестирование, развертывание. Промыть и повторить.
Это невозможно. Что происходит, когда я пишу свою операционную систему со странным компилятором C?
Тем не менее, чтобы быть переносимым, вам необходимо:
Некоторые вещи помогут:
Знайте платформы, для которых вы собираетесь поставлять. Если какое-либо соглашение о платформе противоречит стандарту, игнорируйте стандарт. Я серьезно к этому отношусь. Например, если вы используете стандартный конструктор std :: ifstream
, который принимает аргумент char *
, вы не сможете открывать файлы с именами файлов Unicode в Windows - вы должен использовать нестандартную перегрузку wchar_t *
. Функциональность, утраченная из-за невозможности открывать файлы, которые разрешены и легальны на платформе, сильно перевешивает переносимость, полученную при использовании только того, что известно стандарту; в конце концов, важна функциональность, а не соблюдение определенного стандарта.
Избегайте использования библиотек, специфичных для конкретной платформы. Если вы можете реализовать желаемую функциональность, используя только STL и BOOST, действуйте.
Юнит-тестируйте его на каждой платформе во время разработки
Это не прямой ответ на вопрос, а ответ в свете других ответов.
Необходимо сбалансировать требование абсолютной переносимости с ожиданиями пользователей платформы — для Windows, OS X, KDE и Gnome существуют разные базовые рекомендации по HCI/HIG, и ни один из переносимых наборов инструментов с графическим интерфейсом не будет автоматически давать правильные результаты. в каждом (некоторые позволяют применять разные макеты, что является началом).
Промежуточный подход состоит в том, чтобы иметь чисто переносимое ядро с несколькими собственными графическими интерфейсами.
В этом нет необходимости (существует много программного обеспечения, которое работает успешно, несмотря на игнорирование соглашений), но это компромисс, который необходимо учитывать, особенно если существует сильное родное приложение.