Директивы препроцессора #ifdef #define и #undef

162
27 февраля 2019, 08:30

В чем здесь проблема? Почему n всегда равно либо 100 и 100, либо 200 и 200, как ни крути.

#include <stdio.h>
#include <iostream>
using namespace std;
#ifdef A
    #define N 100
#else  
    #define N 200
#endif

int main()
{
    #define A
    int n = N;
    cout << n << endl;
    #undef A
    #define B
    n = N;
    cout << n << endl;
    #undef B
    return 0;
}
Answer 1

Предпроцессор - нужен не для того, что бы писать программу времени выполнения, а для того, что бы сгенерировать код(программу) времени компиляции. Например создать две сборки debug и release. Или в вашем случае два модуля, один с N=100 и второй N=200. Всё верно. Или так или так, но не две одновременно (условно).

Предпроцессор не умеет делать "процедуры и функции" процессинга в широком смысле (функции аргумента - существуют). Т.е. реальный код генерируется за один проход. Если один раз сделано #define N 100 то N не изменит значение до тех пор пока снова не встретится define N или undef N (зачёркиваем "условно"). Другого способа повлиять - нету.

В коде все директивы выполняются последовательно. Т.е. код

#ifdef A
    #define N 100
#else  
    #define N 200
#endif

int main()
{
    #define A
    int n = N;
    cout << n << endl;
    #undef A
    #define B
    n = N;
    cout << n << endl;
    #undef B
    return 0;
}

Является "виртуальным" в реальности предпроцессор делает из него такой код

// N = 200
int main()
{
    // A задано, N без изменений
    int n = 200;
    cout << n << endl;
    // B задано, А не_задано, N без изменений
    n = 200;
    cout << n << endl;
    return 0;
}

Но на самом деле всё "условно", что бы ваш код работал, вам его нужно поправить так вставив фрагмент ниже, или сохранить это фрагмент в файл например def_A.h c таким кодом

#ifdef A
    #define N 100
#else  
    #define N 200
#endif

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

int main()
{
    #define A
    #include "def_A.h"
    //#ifdef A
    //    #define N 100
    //#else  
    //    #define N 200
    //#endif
    int n = N;
    cout << n << endl;
    #undef A
    #define B
    #include "def_A.h"
    //#ifdef A
    //    #define N 100
    //#else  
    //    #define N 200
    //#endif
    n = N;
    cout << n << endl;
    #undef B
    return 0;
}

Вставил комментраием то, что делает директива include. Приводить какой код сгенерирует предпроцессор не буду, думаю это очевидно.

И как последний штрих, допишите перед #define N 100, а лучше перед #ifdef A директиву #undef N. Это не обязательно, это уберет warning или hint с уведомлением что "переопределение N не совпадает с предыдущим предопределением".

Answer 2

Макроопределения не меняются по ходу действия. Идет обработка препроцессором. Доходит дело до блока

#ifdef A
    #define N 100
#else  
    #define N 200
#endif

Препроцессор соображает: определено ли A? Нет? Отлично, так и запишем, что далее N меняется на 200. И дальше, когда дело доходит до n = N;, это N заменяется на уже записанное в своих каких-то внутренних таблицах препроцессора 200 независимо от других макроопределений.

Answer 3

В качестве иллюстрации к ответу от Harry. Возьмем простую программу, полностью аналог вашей, только вместо препроцессора - процессор:

int N;
bool b = true;
if (b)
  N = 100;
else
  N = 200;
b = false;
cout << N;

Что будет напечатано? По вашей логике - 200, но напечатается, естественно, 100.

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

READ ALSO
Как получить размер матрицы и её элементы от пользователя?

Как получить размер матрицы и её элементы от пользователя?

Как мне сделать так, чтобы размер матрицы и значение её элементов я вводил сам (то есть динамически)?

146
Создание меню выбора C++

Создание меню выбора C++

вообщем нужно создать меню выбора пунктов, например:

170
Заполнить матрицу по спирали

Заполнить матрицу по спирали

Не смог найти библиотеку, которая позволяет заполнить матрицу по спирали, например так:

162
Обработка нажатия кнопки ImageButton

Обработка нажатия кнопки ImageButton

Пишу приложение под androidСоздал отдельное activity для словаря(приложение будет переводить слова из существующей базы и при подключении интернета...

165