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