2015-09-26 2 views
-1

Я недавно видел некоторый код, как это:Понимание макро расширения

#define JOIN(lhs, rhs) JOIN_(lhs, rhs) 
#define JOIN_(lhs, rhs) JOIN__(lhs, rhs) 
#define JOIN__(lhs, rhs) lhs##rhs 

я тестировал код, называя подобные этим:

JOIN(Foo, 0); 
JOIN_(Foo, 1); 
JOIN__(Foo, 2); 

JOIN(Foo, JOIN(A,B)); 
JOIN_(Foo, JOIN(A,B)); 
JOIN__(Foo, JOIN(A,B)); 

макросы расшириться в следующих символов:

Foo0 
Foo1 
Foo2 
FooAB 
FooAB 
FooJOIN 

Я получаю цель, она решает аргументы по-разному. Вызов любого из вариантов JOIN явно не совпадает с последним случаем. Но как расширяются эти макросы? Почему аргументы ведут себя по-другому?

Edit: Here's файл

+0

Я думаю, последний макрос 'JOIN __ (Foo, JOIN (A, B)); ' должен быть расширен как «FooJOIN (A, B)», а не только «FooJOIN», просим пояснить. –

+0

Возможно. Я получаю предупреждение: неявное объявление функции «FooJOIN» недопустимо в C99', поэтому я не вижу, какие аргументы он получает. Но то, что вы говорите, имеет смысл. –

ответ

1

EDIT

3.9.6 Довод Prescan

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

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

Например, если у вас есть

#define AFTERX(x) X_ ## x 
#define XAFTERX(x) AFTERX(x) 
#define TABLESIZE 1024 
#define BUFSIZE TABLESIZE 

затем AFTERX (BUFSIZE) расширяется до X_BUFSIZE и XAFTERX (BUFSIZE) расширяется до X_1024. (Не X_TABLESIZE. Prescan всегда делает полное разложение.)

case1

#define JOIN__(lhs, rhs) lhs##rhs =>, так как он имеет маркер оператора оклейки, это будет конкатенацией макро аргументы тех, которые не являются полностью макрорасширением перед тем, замещенным , ->, который является плохим способом расширения, и на первом месте мы не знаем, какие будут аргументы, которые ему будут переданы, он не будет ждать своего расширения, и он просто будет его конкатенацией.

следовательно, когда вы позвоните JOIN__(Foo, JOIN(A,B));, он не позволит JOIN(A,B) расшириться, и он будет соединять его с FOOJOIN (A, B).

Вариант 2 сейчас, с другой стороны, не #define JOIN_(lhs, rhs) JOIN__(lhs, rhs) => здесь, нет маркеров оператора вставки, Macro аргументов полностью макро вспененный, прежде чем они подставляются в тело макроса. следовательно, это позволит расширять lhs и rhs и вызывать с расширенными параметрами JOIN__(FOO,AB), поэтому теперь JOIN__ имеет оператор склейки маркеров, он просто объединяет его аргументы FOO и AB, то есть FOOAB. который является подходящим способом для этого.

CASE3 #define JOIN(lhs, rhs) JOIN_(lhs, rhs) => такой же, как CASE2.

Надеюсь, это объясняет причину парадигмы многоуровневого расширения.

ОРИГИНАЛ Оператор препроцессора ## обеспечивает способ объединения фактических аргументов во время макрорасширения. Если параметр в заменяемом тексте смещен рядом с ##, параметр заменяется фактическим аргументом, ## и окружающее пробел удаляются, а результат повторно просматривается. Например, макро-паста объединяет два аргумента:

#define paste(front, back) front ## back 

so paste(name, 1) creates the token name1. 
+0

Я знаю об операторе маркировки. Я спрашиваю об этой многоуровневой парадигме расширения, а не о конкатенации –

+0

@ AndréFratelli: Пожалуйста, найдите обновленный ответ для «многоуровневой парадигмы расширения». Надеюсь, он объяснит, что вы ищете. –

+0

Удивительный ответ, действительно тщательный. –

1

Оператор ## разметить не оценивает (макро-расширение) аргументов. Разнообразные расширения макросов do оценивают аргументы, и поэтому вы ожидаете (оцениваете) вывод для первых случаев.

Технически, макро JOIN_ не является необходимым, так как lhs и rhs в JOIN оцениваются при расширении JOIN__. Это было бы достаточно:

#define JOIN(lhs, rhs) JOIN__(lhs, rhs) 
#define JOIN__(lhs, rhs) lhs##rhs 
+0

Я честно не могу найти ситуацию, в которой вы ошибаетесь, но почему код был написан так? –

+0

См. Мое редактирование. Я включил исходный код –

+0

@ AndréFratelli - Кто знает? Люди делают странные вещи ... Но я не вижу причин, чтобы код был написан таким образом. – owacoder

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