Подтвердить что ты не робот

Дос и Донны условной компиляции

Когда делает условную компиляцию хорошей идеей и когда это ужасно плохая идея?

Посредством условного компиляции я имею в виду использование #ifdef для компиляции определенных битов кода в определенных условиях. Сами #defined могут быть либо в общем файле заголовка, либо через директиву -D компилятора.

4b9b3361

Ответ 1

Хорошие идеи:

  • защита заголовков (вы не можете сделать намного лучше для переносимости)
  • условная реализация (жонглирование различиями в платформе)
  • отладить специальные проверки (утверждает и т.д.)
  • за предложение: extern "C" { и }, чтобы одни и те же заголовки могли использоваться реализацией С++ и клиентами C API

Плохая идея:

  • изменение API между флагами компиляции, поскольку это заставляет клиента изменять его использование с теми же флагами компиляции... urk!

Ответ 2

В принципе, вы должны попытаться сохранить минимальный код, который условно скомпилирован, потому что вы должны пытаться проверить все это и иметь множество условий, что усложняет работу. Это также снижает читаемость кода; условная компиляция целых файлов более ясна, например, путем размещения кода, специфичного для конкретной платформы, в отдельном файле для каждой платформы и с тем, чтобы все они имели один и тот же API с точки зрения остальной части проблемы. Также старайтесь избегать использования его в заголовках функций; опять же, потому что это место, где это особенно запутывает.

Но это не означает, что вы никогда не должны использовать условную компиляцию. Просто старайтесь держать его коротким и минимальным. (Где я могу, я использую условную компиляцию для управления определениями других макросов, которые тогда просто используются в остальной части кода, что, по-видимому, для меня яснее.)

Ответ 3

Не помещайте ifdef в свой код.
Это очень трудно читать и понимать. Пожалуйста, сделайте код таким же простым для понимания, насколько это возможно для сопровождающего (он знает, где вы живете и владеете топором).

Скрыть условный код в отдельных функциях и использовать ifdef для определения того, какие функции используются.

DONT используйте часть else для определения. Если вы говорите, что вы говорите, что одна платформа уникальна, а все остальные одинаковы. Это маловероятно, более вероятно, что вы знаете, что происходит на нескольких платформах, но вы должны использовать раздел #else для привязки #error, поэтому, когда он переносится на новую платформу, разработчику необходимо явно установить условие для его платформу.

x.h

#if defined(WINDOWS)
#define   MyPlatfromSleepSeconds(x)  sleep(x * 1000)
#elif defined (UNIX)
#define   MyPlatfromSleepSeconds(x)  Sleep(x)
#else
#error "Please define appropriate sleep for your platform"
#endif

Не пытайтесь развернуть макрос на несколько строк кода. Это приводит к безумию.

p.h

#if defined(SOLARIS_3_1_1)
#define  DO_SOME_TASK(x,y)      doPartA(x);   \
                                doPartB(y);   \
                                couple(x,y)
#elif defined(WINDOWS)
#define  DO_SOME_TASK(x,y)      doAndCouple(x,y)
#else
#error "Please define appropriate DO_SOME_TASK for your platform"
#endif

Если вы разрабатываете код на окнах, а затем тестируете на solaris 3_1_1, вы можете обнаружить неожиданные ошибки, когда люди делают такие вещи, как:

int loop;
for(loop = 0;loop < 10;++loop)
    DO_SOME_TASK(loop,loop);             // Windows works fine()
                                         // Solaras. Only doPartA() is in the loop.
                                         //          The other statements are done when the loop finishes 

Ответ 4

Это плохая идея, когда вы не знаете, что делаете. Это может быть хорошей идеей, когда вы решаете проблему таким образом:).

То, как вы описываете условную компиляцию, включает в себя охранники, является ее частью. Это не только хорошая идея. Это способ избежать ошибок компиляции.

Для меня условная компиляция также является способом нацеливания нескольких компиляторов и операционных систем. Я участвую в lib, который должен быть скомпилирован в Windows XP и новее, 32 или 64 бит, используя MinGW и Visual С++, на Linux 32 и 64 бит, используя gcc/g++ и на MacOS, используя I-don't-know -что (я не поддерживаю это, но я предполагаю, что это gcc-порт). Без условий препроцессора было бы практически невозможно создать один исходный файл, который можно скомпилировать в любом месте.

Ответ 5

Другим прагматичным использованием условных компиляций является "прокомментировать" разделы кода, содержащие стандартные комментарии "С" (т.е./* */). Некоторые компиляторы не допускают вложения этих комментариев, например:

/* comment out block of code

.... code ....
/* This is a standard 
 * comment.
 */  ... oopos!  Some compilers try to compile code after this closing comment.
.... code ....

end of block of code*/

(Как вы можете видеть в подсветке синтаксиса, StackOverflow не вставляет комментарии.)

вместо этого вы можете использовать #ifdef для получения правильного эффекта, например:

#ifdef _NOT_DEFINED_

.... code ....
/* This is a standard 
 * comment.
 */  
.... code ....

#endif

Ответ 6

В прошлом, если вы хотели создать действительно портативный код, вам придется прибегнуть к какой-то форме условной компиляции. При наличии распространения портативных библиотек (таких как APR, boost и т.д.) Эта причина имеет небольшой вес IMHO. Если вы используете условную компиляцию, просто скомпилируйте блоки кода, которые не нужны для конкретных сборок, вы должны действительно пересмотреть свой дизайн - я должен представить, что это станет кошмаром для поддержания.

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

Ответ 7

Хорошее/обоснованное использование основано на анализе затрат и результатов. Очевидно, что люди здесь очень осознают риски:

  • при связывании объектов, которые видели разные версии классов, функций и т.д.
  • при сложном понимании кода, проверке и причине о

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

  • защита заголовков
  • для отдельных программных "экосистем", таких как Linux в сравнении с Windows, Visual С++ и GCC, оптимизация по конкретным процессорам, иногда размер слов и коэффициенты суждения (хотя с С++ вы часто можете определить их при компиляции с помощью хакерства шаблонов, но что может оказаться более беспорядочным) - абстрагирует различия на более низком уровне, чтобы обеспечить согласованный API в этих средах.
  • взаимодействие с существующим кодом, использующим препроцессор, определяет выбор версий API, стандартов, поведения, безопасности потоков, протоколов и т.д. (грустно, но верно).
  • которая может использовать дополнительные функции, когда они доступны (подумайте о сценариях GNU configure и всех тестах, которые они выполняют на интерфейсах ОС и т.д.)
  • запросить создание дополнительного кода в модуле перевода, например добавление main() для автономного приложения или без библиотеки
  • контроль включения кода для различных режимов логической сборки, таких как debug и release

Ответ 8

Это всегда плохая идея. То, что он делает, эффективно создает несколько версий исходного кода, все из которых необходимо протестировать, что является, по меньшей мере, болью. К сожалению, как и многие плохие вещи, это иногда неизбежно. Я использую его в очень небольших количествах при написании кода, который нужно портировать между Windows и Linux, но если бы я сам это делал, я бы рассмотрел альтернативы, например, наличие двух отдельных поддеревьев разработки.