Как написать портативный код в C++?

Каковы вещи, которые я должен иметь в виду для написания портативного кода? Так как я - новичок C++, я хочу практиковать его с начала.

Спасибо.

28
задан understack 23 June 2010 в 16:30
поделиться

12 ответов

  • научиться использовать стандартную библиотеку
  • читать книги (например, эту)
  • когда вы будете опытны, научитесь использовать boost
17
ответ дан 28 November 2019 в 02:55
поделиться

Храните специфичный для платформы код отдельно от повторно используемого кода, предпочтительно в другом файле, но, по крайней мере, в другой функции. Если у вас начнутся повсюду #if WIN32 и #if CYGWIN и #if BSD , вас ждет кошмар обслуживания.

Затем скомпилируйте как минимум на двух разных платформах как можно раньше и чаще. Типичный выбор - Visual C ++ в Windows и gcc в Linux. Поскольку ни системные библиотеки, ни компилятор не являются общими, вы поймаете непереносимый код до того, как он глубоко укоренится в вашем дизайне.

14
ответ дан 28 November 2019 в 02:55
поделиться

Для начала напишите программы командной строки. Когда будете готовы, найдите кроссплатформенный набор инструментов для работы с окнами, например Qt .

Если вы заинтересованы в написании многоязычного кода, используйте стороннюю библиотеку Unicode, такую ​​как ICU , а не полагайтесь на библиотеки для конкретной платформы.

5
ответ дан 28 November 2019 в 02:55
поделиться

О чем мне следует помнить при написании переносимого кода?

  1. Держите поблизости несколько компиляторов, регулярно тестируйте код на целевых платформах. Если вы создаете кроссплатформенное программное обеспечение для windows, windows / linux, используйте mingw, visual studio express (т.е. «компилятор microsoft») и установку linux с g ++ (или используйте виртуальную машину). Даже если ваш код идеален, у компилятора может быть какая-то неожиданная причуда. Например, некоторые версии компилятора ms имеют ограничение на размер строковых констант, которого нет в gcc.
  2. Не полагайтесь на размеры стандартных типов. Например, в msvc sizeof (wchar_t) составляет 2 байта. При установке linux это может быть 4 байта. Используйте sizeof (если он вам нужен) или постарайтесь избежать использования size любого типа в вашем коде. И вы не должны предполагать, что указатель имеет размер 4 байта (передача указателя пользовательских данных в сценарий вызова API) - это будет 8 байтов на 64 бита.
  3. Не используйте специфичные для компилятора прагмы, макросы и расширения. Например, избегайте «#pragma once».
  4. Не используйте расширения стандартной библиотеки (предоставленные разработчиком компилятора). Однако это больше применимо к функциям библиотеки C. Например, компилятор MS предоставляет несколько «безопасных» (например, strcpy_s) версий стандартных подпрограмм в стиле C. Что, конечно, не будет доступно на других платформах.
  5. Будьте очень осторожны, если решите использовать процедуры в стиле C (например, sprintf) в коде C ++. (Я знаю , что это считается плохой практикой, но в некоторых сценариях это полезно) У них немного разные реализации, расширения и другое количество параметров.Например, sprintf может иметь разные дополнительные форматы, которые по-разному реализуются на разных платформах. Например, в прошлый раз, когда я проверял, "% S" ведет себя по-разному на msvc и gcc в подпрограмме vswprintf.
  6. Не полагайтесь на специфичные для компилятора типы данных, такие как __int32. Очень вероятно, что вам понадобится какой-то тип, длина которого гарантированно будет 4 байта (или что-то в этом роде) - используйте typedef в сочетании с условной компиляцией ("#ifdef WIN32"). ИЛИ используйте типы, предоставленные кроссплатформенной библиотекой. Например, SDL предоставляет такие типы, как Uint8, Qt 4 имеет quint32 и т. Д. Это довольно распространенная практика.
  7. Избегайте прямых вызовов ОС. Используйте стандартные функции для доступа к файлам.
  8. Когда вам нужно использовать специфичные для ОС вызовы, используйте условную компиляцию (#ifdef WIN32 и т. Д.)
  9. Старайтесь использовать одну и ту же систему сборки на всех платформах. В Linux нет MSBuild. Используйте gnumake, cmake, scons или qmake. Хотя в некоторых из этих систем вам придется кодировать флаги для разных компиляторов, можно будет использовать один и тот же сценарий везде. Например, он отлично работает с SConstructs. А поддерживать один сценарий сборки для всех платформ может быть проще, чем синхронизировать изменения в разных системах сборки.
  10. Для всех операций, требующих взаимодействия с операционной системой (Gui, манипуляции с файлами), используйте кроссплатформенные библиотеки. Qt - хороший выбор.
13
ответ дан 28 November 2019 в 02:55
поделиться

Другие говорили это раньше, но вот мой взгляд на это:

1) Вам нужен C ++? Это не лучший язык для написания переносимого кода, потому что он близок к «голому железу». Вам могут подойти Java, Python, Perl, PHP или Javascript.

2) Если вам нужен C ++, не пытайтесь писать полностью переносимый код, в любом случае это практически невозможно. Вместо этого заранее решите, какие платформы вы хотите поддерживать. Например: Linux, MacOS X, Windows

3) Убедитесь, что вы постоянно тестируете свой код на всех выбранных платформах. Не создавайте просто для Windows и ожидайте, что просто скомпилируете версию для Linux «когда это будет сделано». Ежедневно компилируйте на всех платформах и постоянно проверяйте их на наличие проблем.

2
ответ дан 28 November 2019 в 02:55
поделиться

Для обучения старайтесь избегать книг, которые концентрируются на одной реализации. В некоторых случаях введение или первая глава дадут вам некоторые инструкции о том, как получить или использовать языковую реализацию; если в нем упоминается более одной реализации, вы, вероятно, в порядке.

Получите справочник, не зависящий от платформы. Страуструп Язык программирования C ++ является прекрасным справочником, хотя это не очень хорошая книга для новичков, из которой можно учиться. Не полагайтесь на ссылки для данной реализации. Например, MSDN полезен, но его основное внимание уделяется тому, как писать программы для Windows с использованием Visual C ++, а не тому, как писать программы, которые будут компилироваться и запускаться где угодно.

Чтобы написать что-нибудь действительно полезное, вам придется заняться непереносимым кодом. Постарайтесь выработать привычку отделять код пользовательского интерфейса от всего остального, так как именно там у вас будет наименьшая совместимость. Чем меньше кода вам придется менять между платформами, тем более переносимым будет ваш код.

1
ответ дан 28 November 2019 в 02:55
поделиться

Некоторые рекомендации:

  1. Держите бизнес-часть кода и графический интерфейс отдельно.
  2. Избегайте использования костылей, специфичных для компилятора (#pragma и т. Д.).
  3. Используйте обычные выражения, которые не изменяют поведение компилятора / платформы, вместо симпатичных уловок с манипуляциями с битами.
  4. Если он касается оборудования, он принадлежит к драйверу устройства.
  5. Используйте заголовки типов данных, такие как types.h (uint32_t и т. Д.).
  6. Используйте уровень абстракции операционной системы, чтобы не вызывать вызовы операционной системы напрямую.

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

Не весь код нужно писать таким образом. Если вы разрабатываете свое приложение по модульному принципу с четко определенными границами ответственности, то 90-95% кода можно переносить без проблем. Затем просто изолируйте 5–10% в очень ограниченной области, которую необходимо настроить для новой платформы.

2
ответ дан 28 November 2019 в 02:55
поделиться

По возможности используйте типы STL. Будьте осторожны при использовании системно-зависимых типов и API. Например, не используйте такие типы, как UINT и DWORD в Windows.

Вы можете использовать такую ​​библиотеку, как boost, чтобы упростить вам написание переносимого кода. Если вам нужен графический интерфейс, подумайте об использовании кросс-платформенного инструментария, такого как Qt.

Иногда вам нужно написать код для конкретной платформы, и в таких случаях вы можете сделать что-то вроде этого:

#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
4
ответ дан 28 November 2019 в 02:55
поделиться

Независимый от ОС код удивительно трудно сделать на 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++, не прибегая к условной компиляции.

1
ответ дан 28 November 2019 в 02:55
поделиться

хорошая идея - использовать системные вызовы POSIX. таким образом вам не придется иметь дело с различными способами создания потоков или использования мьютексов и сигналов.

проблема в том, что Windows не совсем совместима с POSIX, но существуют библиотеки, реализующие определенные функции POSIX, например, эта: [1]: http://sourceware.org/pthreads-win32/

0
ответ дан 28 November 2019 в 02:55
поделиться

По возможности скомпилируйте весь свой код как минимум с двумя разными компиляторами.

1
ответ дан 28 November 2019 в 02:55
поделиться

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

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

А вот основные категории, которые я могу придумать.

Расширения компилятора

Как, например, использование массивов переменных:

void func(int const n)
{
  int array[n];
}

Это нестандартно, но, тем не менее, многие компиляторы поддерживают его, потому что это просто практично.

Расширения стандартных библиотек

Многие реализации стандартных библиотек предоставляют std :: hash_map , который никогда не указывался. Если вы используете его в своем коде, он не переносится.

Современная тенденция заключается в том, чтобы спрятать этот материал в пространстве имен std :: tr1 , чтобы программисты знали, что это расширение.

Также имейте в виду, что многие определяют typedef или макросы, которые не являются универсальными (например, PRETTY_FUNCTION ). Стандарт не определяет никаких макросов, и очень мало typedef.

Зависит от платформы

Например, размер и выравнивание int или double не указаны в стандарте. Если вы занимаетесь бит-твиддлингом и ожидаете, что он будет иметь 32 бита, вы будете облажались на 64-битных платформах, даже не меняя компилятор.

Platform API

Наши программы предназначены для компиляции, и они часто предназначены для взаимодействия с компьютером, на котором они работают:

  • для доступа к оборудованию
  • для доступа к файловой системе
  • для доступ к экрану

Вам нужно найти кроссплатформенные переносимые API или создать свой собственный. Отметьте некоторые библиотеки в списке ниже.

Библиотеки

Большинство хорошо написанных библиотек в значительной степени переносимы, просто убедитесь, что они поддерживают:

  • интересующие вас компиляторы
  • платформы, которые вам интересны

Хорошие библиотеки включают:

  • ] Apache (собрание библиотек)
  • Boost
  • Qt (для графики)
  • ICU (для обработки Unicode)

Остальные, которые вам нужно изучить ... и это требует времени.

Я не думаю, что здесь есть идеальный ответ. Но поскольку идеальная переносимость невозможна, вам нужно решить, какие компиляторы и платформу вы хотите поддерживать.

Для платформы вы должны начать с Windows и одного варианта Linux. Для компиляторов выберите любые два (с Comeau, если вы можете себе это позволить).

2
ответ дан 28 November 2019 в 02:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: