Можете ли вы передать макрос другому макросу в качестве аргумента без раскрытия исходного макроса?

Предыстория. Мой код, который я не могу опубликовать здесь, в конечном итоге будет запускаться на микроконтроллере, а макросы просто предлагают способ создания нескольких функций определения контактов с помощью одного механизма определения одного макроса. Я использую окна и gcc, чтобы экспериментировать с ними.

Я старался максимально абстрагироваться от проблемы. Я использую консольные функции std, потому что мне удобно отображать их в окне консоли. Таким образом, я также сохраняю файл как .cpp и компилирую его с помощью g ++ в Windows.

Скажем, я установил свой код следующим образом:

#define MACRO2(_x)  foo##_x(_x)
#define MACRO1(_x)  MACRO2(_x)
#define BAR         3   

void fooBAR(int num)
{
    std::cout << num << std::endl;
}

Если я запустил следующий код (рабочий пример)

int main()
{
    MACRO2(BAR);
    return 0;
}

сначала BAR вставляется в ## _ x и, таким образом, определяет имя функции, которая должна быть вызвана, а затем BAR вставляется в качестве аргумента этой функции и расширяется до своего значения, поэтому мы получаем fooBAR (3). Код работает, ошибок нет.

Теперь, если я попытаюсь добавить макрос между ними (а это реальная ситуация, с которой я столкнулся по причинам, в которые я не могу войти), мой код будет выглядеть так:

int main()
{
    MACRO1(BAR);
    return 0;
}

Но этот код вызывает ошибку, потому что, когда MACRO1 (BAR) заменяется MACRO2 (BAR), (BAR) затем расширяется до 3, а MACRO2 (3) приводит к foo3 (3), который не определен, что подтверждается журнал ошибок:

ошибка: 'foo3' не был объявлен в этой области

Итак, требования следующие:

  1. Мне нужно передать BAR в MACRO1, и его нужно передать в MACRO2 без расширения
  2. Слово BAR должно оставаться таким, какое оно есть, я знаю, что могу использовать ##, чтобы предотвратить его расширение, но тогда мне нужно будет добавить символ в BAR, и вызов функции больше не будет работать.

Можно ли как-то это сделать? Передать макрос другому макросу в качестве аргумента без раскрытия исходного макроса в процессе?


person Vincent    schedule 10.09.2019    source источник
comment
Я не на 100 процентов, но разве это не похоже на обман этот?   -  person 500 - Internal Server Error    schedule 10.09.2019
comment
Обратите внимание, что ваш язык не C.   -  person n. 1.8e9-where's-my-share m.    schedule 10.09.2019
comment
@ 500-InternalServerError, этот вопрос действительно кажется тем же самым, но один ответ на самом деле не отвечает на вопрос, поставленный там ... или здесь.   -  person John Bollinger    schedule 10.09.2019


Ответы (2)


Но этот код вызывает ошибку, потому что, когда MACRO1 (BAR) заменяется MACRO2 (BAR), (BAR) затем расширяется до 3, а MACRO2 (3) приводит к foo3 (3)

да. Это указанное поведение препроцессора для вашего конкретного набора макросов.

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

Можно ли как-то это сделать? Передать макрос другому макросу в качестве аргумента без раскрытия исходного макроса в процессе?

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

#define MACRO2(_x)        foo##_x(_x)
#define MACRO1(_x,dummy)  MACRO2(_x##dummy)
#define BAR               3   

int main()
{
    MACRO1(BAR,);
    return 0;
}

Это расширяется до

int main()
{
    fooBAR(3);
    return 0;
}

Если вы хотите избежать лишней запятой, вы можете сделать это, сделав MACRO1 вариативным:

#define MACRO2(_x)      foo##_x(_x)
#define MACRO1(_x,...)  MACRO2(_x##__VA_ARGS__)
#define BAR             3   

int main()
{
    MACRO1(BAR);
    return 0;
}

Это расширяется до того же, что и другое.

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

person John Bollinger    schedule 10.09.2019

Один из способов добиться этого - немного изменить определение BAR.

#define MACRO2(_x)  foo##_x(_x())
#define MACRO1(_x)  MACRO2(_x)
#define BAR()       3   
person n. 1.8e9-where's-my-share m.    schedule 10.09.2019