2013-04-07 2 views
6

У меня есть этот код, который работает:C препроцессора с использованием закрывающей скобки родителя макросъемки

#include <stdio.h> 
#define A(x) x B 
#define B(x) C(x, 
#define C(x,y) y x) 
int main(void) { 
    printf(A("1") ("2") "3"); 
} 

Он печатает 132 (в точке A макроса поменять вещь, которая следует его параметрам в скобках со всем после этого до другого закрывающей скобки)

Но если я использую это в другой макрос:

#define Z(x) x 
printf(Z(A("1") ("2") "3")); 

Я получаю ошибку компиляции Msgstr "Неограниченный функциональный вызов макроса".

Я понимаю, что это происходит потому, что компилятор пытается обрабатывать аргументы Z самостоятельно, но мне нужно использовать его закрывающую скобку в качестве маркера. Есть ли способ сделать эту работу внутри макросов? Изменение синтаксиса вызова на самом деле не является вариантом.


p.s. Прежде чем я получу какие-либо ответы, расскажу о том, что ужасно, что нужно делать, будьте уверены: это не настоящий код. Это проблема, возникшая при создании игрушечной программы, которая использует define для моделирования нового языка внутри C.

ответ

3

Самый простой способ увидеть, что происходит, - немного изменить тестовый пример.

#define A(x) x B 
#define B(x) C(x, 
#define C(x,y) y x] /* note close square bracket instead of close paren */ 

Y(A(1)(2)3) 

preprocesses to Y(1 3 2]. Это происходит потому, что промежуточная стадия расширения выглядела как

Y(1 C(2,3) 

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

Теперь, что происходит по-другому, если A(1)(2)3 находится внутри аргумента макроса?

#define Z(x) x 
Z(A(1)(2)3) 

Из argument prescan, аналогичный промежуточный этап расширения является не

Z(1 C(2,3) 

а

1 C(2,3 

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

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

#define _A(x) x B 
#define B(x) C(x, 
#define C(x,y) y x) 

#define Z(x) ZZ((_##x)) 
#define ZZ(x) ZZZ x 
#define ZZZ(x) [x] 

Z(A(1)(2)3) 

к [1 3 2] предварительно обрабатывает. Мы используем оператор точечной пасты, чтобы предотвратить аргумент Z, поэтому мы можем добавить временный дополнительный набор круглых скобок для использования C. ZZ и ZZZ, затем отмените их снова. Уловка заключается в том, что это ошибка, если вы не вставляете x с что-то, поэтому мы должны добавить ведущее подчеркивание к определению A, и это будет ошибка, если первый токен аргумента Z не то, что может быть символическим, - вставлено после подчеркивания.

Возможно, вы захотите рассмотреть вопрос об использовании M4 вместо того, чтобы пытаться использовать это в препроцессоре C.

+0

Спасибо за подробное объяснение. К сожалению, решение не применимо к моей точной проблеме (мне все еще нужны другие макросы внутри Z для расширения). Что касается M4, хорошо, если бы это был настоящий проект, я бы согласился, но задача состоит в том, чтобы сделать это с причудливым препроцессором C! Как связанный вопрос, можно ли использовать скобки '()' вместо '[]'? то есть есть способ избежать символов скобок? – Dave

+0

Я не понимаю ваш родственный вопрос. Я просто использовал квадратные скобки для иллюстрации; что касается препроцессора, они не имеют никакого особого значения. – zwol

+0

Я имею в виду эту строку: '#define C (x, y) y x]/* обратите внимание на квадратную скобку вместо закрытого символа * /' как ')', она ломается. – Dave

0

Речь идет о порядке обработки макросов. Самое простое решение - добавить дополнительные круглые скобки вокруг аргумента Z.

printf(Z((A("1")("2") "3"))); 
+0

Но это было бы возможно сделать это * без *, требующего другого синтаксиса при его использовании? (возможно, сделав 'Z' в более сложный макрос). – Dave

1

eclipse cdt отлично подходит для отладки ваших вопросов. для затмения, просто наведите указатель мыши на макрос, чтобы начать. здесь detialed информация о нем:

C/C++ Software Development with Eclipse >> 2.1.7. Macro Expansion

для второго макроса, затмение показывает следующее:

int main (void) { 
    printf(Z(A("1") ("2") "3")); 
} 

enter image description here enter image description here enter image description here enter image description here enter image description here

Spottin g Ошибка

Уведомление в расширении # 3 C («2», «3« просто »исчезает. Я беру это как способ CDT сказать «список неиспользуемых аргументов». В любом случае, если он исчезнет, ​​это метод, который я предпочитаю принимать при отладке макросов.

  • Использование этого инструмента дает понять, что в расширении №2 (третье изображение) у нас есть нескончаемый набор скобок, таким образом обнаруживая ошибку.

Понимание решения

После пустячный вокруг немного, используя этот инструмент, я думаю, что это то, что вы после:

printf(Z((A("1") ("2") "3"))); 

yields (using gcc -E main.c -c) 

printf(("1" "3" "2")); 

enter image description here

Смежные вопросы