Преимущества условного препроцессора перед условными операторами

Я никогда не работал с #if, #ifdef, #ifndef, #else, #elif и #endif.

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

#include<iostream>
int main()
{
    int i = 0;

    #if i == 0
         std::cout<<"This";
    #else
         std::cout<<"That";
    #endif
    return 0;
}

через это:

#include<iostream>
int main()
{
    int i = 0;

    if (i == 0)
         std::cout<<"This";
    else
         std::cout<<"That";
    return 0;
}

Кроме того, когда использовать / не использовать условный препроцессор?


person kishoredbn    schedule 09.06.2013    source источник
comment
Для начала, if оценивается во время выполнения, а #if оценивается до времени компиляции.   -  person Aiias    schedule 09.06.2013
comment
stackoverflow.com/help/dont-ask   -  person xaxxon    schedule 09.06.2013
comment
@xaxxon: Вы можете объяснить, почему эта ссылка актуальна?   -  person Blender    schedule 09.06.2013
comment
@Blender конечно. I would like to participate in a discussion about ______”, then you should not be asking here iKishore хочет принять участие в обсуждении относительных преимуществ использования условного препроцессора.   -  person xaxxon    schedule 09.06.2013
comment
В этом (и во многих) случаях, если вы включите оптимизацию в своем компиляторе, они выдадут тот же результирующий двоичный файл. Однако в вашем первом примере есть проблема с синтаксисом, поскольку #if не может работать с обычными переменными.   -  person Joachim Isaksson    schedule 09.06.2013
comment
@xaxxon Я этого не вижу. Вопрос спрашивает, какой из них и когда следует использовать, но это вполне законный вопрос, на который можно дать ответ, а не начало обсуждения.   -  person    schedule 09.06.2013
comment
@delnan, когда вы МОЖЕТЕ его использовать, возможно. Но когда это использовать, подразумевает суждение и контекст. Когда это не предусмотрено конкретно в контексте вопроса, это инициирует обсуждение, поскольку требует пространных объяснений различных контекстов и относительных достоинств.   -  person xaxxon    schedule 09.06.2013
comment
Ваш код - не C. Сообщество C ++, вероятно, по-другому относится к этой проблеме.   -  person Jens Gustedt    schedule 09.06.2013
comment
@xaxxon Множество вопросов задают, когда его использовать (по сравнению с этим другим) и получают объективные ответы. Два примера: stackoverflow.com/q/2189452/395760 и stackoverflow.com/q/322715/395760   -  person    schedule 09.06.2013
comment
Margin vs padding является объективным, потому что нет возможности использовать одно или другое для достижения тех же результатов. Я бы посоветовал Java-вариант противоречить часто задаваемым вопросам.   -  person xaxxon    schedule 09.06.2013
comment
Если вы перефразируете примеры, чтобы использовать int i = 1;, и запустите их, вы увидите, что результаты совсем другие. В случае #if i вряд ли известен препроцессору и, таким образом, получает значение по умолчанию 0 при оценке #if i == 0.   -  person Bo R    schedule 10.11.2018


Ответы (5)


Условный препроцессор работает не так, как в вашем первом примере.

Понимаете, он работает с константами? Во время компиляции он смотрит на различные условия и вставляет / опускает исходный код в соответствии с ними.

Например:

#define HAS_COMPARISON

int main() {
    #ifdef HAS_COMPARISON
        int i = 0;
        if(i == 0) std::cout << "This";
        else
    #else
        std::cout << "That";
    #endif
}

С установленным define он установит переменную i и выполнит сравнение ... короче говоря, он выведет This. Если вы прокомментируете это определение, весь блок не будет в вашей программе, что означает, что он всегда будет выводить That, без установки переменной или выполнения сравнения.

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

Еще раз: условный препроцессор оценивается во время компиляции, переменные условия оцениваются во время выполнения.

person Refugnic Eternium    schedule 09.06.2013
comment
~ исправьте меня, если я ошибаюсь, это как если HAS_COMPARISON установлен в 0 перед компиляцией, тогда компилятор удаляет блок внутри #else & #endif < / i> как это делается для удаления мертвого кода. - person kishoredbn; 09.06.2013
comment
@iKishore препроцессор удаляет код до того, как его увидит компилятор, что имеет значение, потому что код, который сделан условным, может не компилироваться / вызывать ошибку, когда компилятор видит его (например, из-за ошибок типа или отсутствующих функций) . - person ; 09.06.2013
comment
@iKishore Нет, ты прав. Если для него вообще установлено ЛЮБОЕ значение, #else удаляется, а если #define удаляется из кода, все от #ifdef до #else удаляется. - person Refugnic Eternium; 09.06.2013

Показанный вами пример не кажется полезным из-за отсутствия другой информации. Но вот пример того, что #if полезно.

#if OS == LINUX
//do something
#elif OS == SOLARIS
//do something else
#else
//
#endif

Ключ в том, что #if оценивается во время компиляции, но if оценивается при запуске программы.

#if BYTE_ORDER == LITTLE_ENDIAN
//do something
#else
//do something else
#endif
person Yu Hao    schedule 09.06.2013

Использование директив препроцессора в этом случае не совсем полезно. Но использование этих директив препроцессора полезно во многих других случаях.

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

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

person Aseem Bansal    schedule 09.06.2013

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

Используйте #ifdef и т. Д., Если вы знаете во время компиляции, что требуется. Условные выражения языка используются, когда вы не знаете, что вам нужно, до времени выполнения.

person John3136    schedule 09.06.2013

Преимущество препроцессора в том, что код выбрасывается. Он не компилируется (что требует времени) и не генерирует машинный код, который будет загружен в оперативную память. Если решение находится в ОЧЕНЬ жестком цикле, выполняемом МНОГО раз, скорость может быть улучшена. Однако не думайте, что это важно, если вы на самом деле не рассчитаете время.

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

person xaxxon    schedule 09.06.2013
comment
Фактически, если условие является константой времени компиляции (и достаточно простой, чтобы препроцессор был вариантом), компилятор обычно может сделать это и удалить мертвый код, если он протестирован с if. - person ; 09.06.2013
comment
Достаточно верно. Всегда полезно помнить о том, насколько умны компиляторы. Люди часто пишут запутанный код, пытаясь провести некоторую преждевременную оптимизацию, а затем понимают, что они не сделали это быстрее и его труднее читать / поддерживать. - person xaxxon; 09.06.2013