Какие вещи я должен иметь в виду, чтобы написать переносимый код? Поскольку я начинаю С++, я хочу практиковать его с самого начала.
Спасибо.
Какие вещи я должен иметь в виду, чтобы написать переносимый код? Поскольку я начинаю С++, я хочу практиковать его с самого начала.
Спасибо.
Сохраняйте код, специфичный для платформы, отдельно от кода многократного использования, предпочтительно в другом файле, но, по крайней мере, в другой функции. Если вы начнете с #if WIN32
и #if CYGWIN
и #if BSD
повсюду, у вас будет кошмар обслуживания.
Затем, скомпилируйте, по крайней мере, две разные платформы рано и часто. Типичными вариантами являются Visual С++ для Windows и gcc в Linux. Поскольку ни системные библиотеки, ни компилятор не используются совместно, вы поймаете непереносимый код, прежде чем он станет глубоко укоренившимся в вашем дизайне.
Какие вещи я должен иметь в виду, чтобы написать переносимый код?
Начните писать программы с командной строкой. Когда вы будете готовы, найдите кросс-платформенный инструментарий для окон, например Qt.
Если вам интересно писать многоязычный код, используйте стороннюю уникодную библиотеку, такую как ICU, а не полагаться на платформу -специальные библиотеки.
Используйте STL-типы, когда это возможно. Будьте осторожны с использованием зависимых от системы типов и API. Например, не используйте такие типы, как UINT и DWORD в Windows.
Вы можете использовать библиотеку, например boost, чтобы упростить запись переносного кода. Если вам нужен GUI, подумайте об использовании кросс-платформенного инструментария, такого как Qt.
Иногда вам нужно написать код конкретной платформы, и в этих случаях вы можете сделать что-то вроде этого:
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
Другие говорили это раньше, но вот мой взгляд на это:
1) Вам нужен С++? Это не лучший язык для написания портативного кода, потому что он близок к голым металлам. Java, Python, Perl, PHP или Javascript могут быть лучше для вас.
2) Если вам нужен С++, не пытайтесь писать полностью переносимый код, это практически невозможно. Вместо этого заранее определите, на каких платформах вы хотите поддерживать. Например: Linux, MacOS X, Windows
3) Убедитесь, что вы постоянно проверяете свой код на всех выбранных платформах. Не просто строить на Windows и рассчитывать просто скомпилировать версию Linux "когда это будет сделано". Компиляция на всех платформах ежедневно и убедитесь, что вы продолжаете тестировать их на наличие проблем.
Необычный программист, вероятно, войдет во множество ловушек, которые мы можем попытаться классифицировать. Но позвольте мне сказать вам сначала: как абсолютное это невозможно.
Проблема в том, что даже код, совместимый со стандартами, может быть не переносимым из-за конкретной проблемы с компилятором.
Теперь вот основные категории, которые я могу придумать с головы.
Расширения компилятора
Как, например, использование массивов переменных:
void func(int const n)
{
int array[n];
}
Это не стандарт, но многие компиляторы поддерживают его, тем не менее, потому что это просто практично.
Расширения стандартных библиотек
Многие стандартные реализации библиотек предоставляют std::hash_map
, которые никогда не указывались. Если вы используете его в своем коде, он не переносится.
Современная тенденция состоит в том, чтобы спрятать этот материал в пространство имен std::tr1
, чтобы программисты знали, что это расширение.
Также имейте в виду, что многие определяют typedef
или макросы, которые не являются общими (например PRETTY_FUNCTION
). Стандартный не указан макросом, и очень мало typedef.
Специфично для платформы
Например, размер и выравнивание int
или double
не указаны в стандарте. Если вы делаете бит-twiddling и ожидаете, что он будет иметь 32 бита, вы будете ввернуты на 64-битные платформы даже без изменения вашего компилятора.
API платформы
Наши программы предназначены для компиляции, и они часто предназначены для взаимодействия с компьютером, на котором они запускаются:
Вам нужно найти кросс-платформенные портативные API-интерфейсы или сворачивать свои собственные. Проверьте некоторые библиотеки в приведенном ниже списке.
Библиотеки
Большинство хорошо написанных библиотек в значительной степени переносимы, просто убедитесь, что они поддерживают:
Хорошие библиотеки включают:
Остальные вам нужно просмотреть... и это требует времени.
Я не думаю, что там есть идеальный ответ. Но поскольку идеальная переносимость невозможна, вам нужно решить, какие компиляторы и платформы вы хотите поддерживать.
Для платформы вы должны начать с Windows и одного Linux-вкуса. Для компиляторов выберите любые два (с Комо, если вы можете себе это позволить).
Некоторые рекомендации:
Иногда вам приходится торговать эффективностью и производительностью, чтобы получить переносимость. Например, если ваш код требует доступа к полям из буфера, вы всегда можете отнести упакованную структуру к указателю буфера. Но это ужасно не переносимо. Поэтому вместо этого вам нужно использовать именованные указатели, рассчитанные с помощью смещений - иногда с кодом обработки выравнивания границы. Не красиво, но портативно. К счастью, вы можете скрыть много вещей с разумным использованием интерфейсов классов.
Не все коды должны быть написаны таким образом. Если вы разрабатываете свое приложение очень модульным способом с четко определенными границами ответственности, то 90-95% кода может быть переносимым без боли. Затем просто выделите 5-10% в очень локализованной области, которая должна быть настроена для новой платформы.
Для обучения старайтесь избегать книг, которые концентрируются на одной реализации. В некоторых случаях введение или ранняя глава дадут вам некоторые инструкции о том, как получить или использовать реализацию языка; если он упоминает более одной реализации, вы, вероятно, в порядке.
Получите справочник, независимый от платформы. Stroustrup Язык программирования С++ - прекрасная ссылка, хотя это не хорошая книга для начинающих, чтобы попытаться учиться. Не полагайтесь на ссылки для данной реализации. Например, MSDN полезен, но основное внимание уделяется тому, как писать программы Windows с использованием Visual С++, а не как писать программы, которые будут компилироваться и выполняться где угодно.
Чтобы написать что-нибудь действительно полезное, вам придется попасть в непереносимый код. Попытайтесь привыкнуть отделять код пользовательского интерфейса от всего остального, так как там, где у вас будет минимальная совместимость. Чем меньше кода вы должны изменить между платформами, тем более портативный ваш код.
Независимый от ОС код на удивление трудно сделать на С++. Рассмотрим этот тривиальный пример:
#include <iostream>
int main(int argc, char** argv) {
std::cout << argv[0] << std::endl;
}
Это совершенно допустимый С++, но он не переносимый, потому что он не будет принимать аргументы командной строки Unicode в Windows. Правильная версия для Windows:
#include <iostream>
int wmain(int argc, wchar_t** argv) {
std::wcout << argv[0] << std::endl;
}
Конечно, это опять-таки непереносимо, работая только на Windows и нестандартно. Таким образом, вы даже не можете написать переносимую функцию main()
в С++, не прибегая к условной компиляции.
Если вы можете, скомпилируйте весь свой код как минимум с двумя разными компиляторами.
хорошая идея - использовать системные вызовы POSIX. таким образом, вам не нужно иметь дело с различными способами создания потоков или использования мьютексов и сигналов.
проблема в том, что Windows не совсем совместима с POSIX, но есть библиотеки, которые реализуют определенные функции POSIX, такие как: [1]: http://sourceware.org/pthreads-win32/