Оператор предварительной обработки "##" - PullRequest
0 голосов
/ 26 января 2019

Узнав о «Операторах препроцессора», я нашел в книге определение:

#define CONCAT(x,y) x##y

Вызов CONCAT(a,b) дает желаемый результат ab. Но CONCAT(a,CONCAT(b,c)) не дает abc, а дает странный вывод.

Книга объясняет это тем, что макропараметры, которым предшествует или следует ## в списке замены, не расширяются во время подстановки. То есть CONCAT(a,CONCAT(b,c)) расширяется до aCONACT(b,c), что может дальше не раскрываться, поскольку нет макроса с именем aCONCAT. Хорошо, я понял, но в книге также упоминалось, что эту проблему можно решить, определив второй макрос, который просто вызывает первый. Пример

#define CONCAT2(x,y) CONCAT(x,y)

Запись CONCAT2(a,CONCAT2(b,c)) теперь дает желаемый список abc.

Но как? Я думаю, что CONCAT2(a,CONCAT2 (b,c)) будет заменено на CONCAT(a,CONCAT2(b,c)), которое будет расширено до aCONCAT2(b,c). Теперь нет макроса с именем aCONCAT2, как в первом случае, тогда как получается желаемый результат?

Это доказательство того, что CONCAT2(a,CONCAT2 (b,c)) работает нормально.

enter image description here

enter image description here Посмотрите, что компилятор не показывает никаких ошибок. За исключением предупреждения об использовании функции getch ().

1 Ответ

0 голосов
/ 26 января 2019

Если у вас есть

#define CONCAT(x,y)   x##y
#define CONCAT2(x,y)  CONCAT(x,y)

тогда, когда препроцессор видит

CONCAT(a,CONCAT(b,c))

он знает, что список замены для CONCAT (x, y) равен x ## y, поэтому он собирается заменить x на a и y на CONCAT (б, в) . Вопрос только в том, расширится ли он a и / или CONCAT (b, c) до замены? a не является макросом, поэтому расширение невозможно, и в списке замен x ## y, y предшествует ##, поэтому расширение аргумента CONCAT (b, c) не выполняется. Таким образом, замена выполняется без раскрытия, и список замен становится ## CONCAT (b, c), а затем, прежде чем проверять наличие дополнительных макросов, обрабатывает ## и список замен становится aCONCAT (b, c).

Если препроцессор видит

CONCAT2(a,CONCAT2(b,c))

он знает, что список замены для CONCAT2 (x, y) - это CONCAT (x, y), поэтому он собирается заменить x на a и y с CONCAT2 (b, c) . Вопрос только в том, расширится ли он a и / или CONCAT2 (b, c) до замены? a не является макросом, поэтому расширение невозможно, и в списке замен CONCAT (x, y), y НЕ предшествует # или ## или после него ##, поэтому CONCAT2 (b, c) ПОЛНОСТЬЮ расширен до замены. Так что CONCAT2 (b, c) расширяется до CONCAT (b, c), который расширяется до b ## c, дальнейшее расширение невозможно, поэтому y заменяется на b # #c. Список замены x ## y становится ## b ## c и либо становится ab ## c, а затем abc, либо становится ## bc, а затем abc.

Если препроцессор видит

CONCAT2(a,CONCAT(b,c))

он знает, что список замены для CONCAT2 (x, y) - это CONCAT (x, y), поэтому он собирается заменить x на a и y с CONCAT (b, c) . Вопрос только в том, расширится ли он a и / или CONCAT (b, c) перед заменой? a не является макросом, поэтому расширение невозможно, и в списке замены CONCAT (x, y), y НЕ предшествует # или ## или после него ##, поэтому CONCAT (b, c) ПОЛНОСТЬЮ расширяется ДО замены. Таким образом, CONCAT (b, c) расширяется до b ## c, дальнейшее расширение невозможно, поэтому y заменяется на b ## c, список замены x ## y становится # # b ## c, либо он становится ab ## c и затем abc, либо становится ## bc, а затем abc.

Если препроцессор видит

CONCAT(a,CONCAT2(b,c))

он знает, что список замены для CONCAT (x, y) равен x ## y, поэтому он собирается заменить x на a и y на CONCAT2 (б, в) * 1 087 *. Вопрос только в том, расширится ли он a и / или CONCAT2 (b, c) до замены? a не является макросом, поэтому расширение невозможно, и в списке замен x ## y, y предшествует ##, поэтому расширение аргумента CONCAT2 (b, c) не выполняется. Таким образом, замена выполняется без раскрытия, и список замен становится ## CONCAT2 (b, c), а затем, прежде чем проверять наличие дополнительных макросов, обрабатывает ## и список замен становится aCONCAT2 (b, c).

Возможно, вы думаете, что

#define CONCAT2(x,y)  CONCAT(x,y)

означает, что

CONCAT2 (x, y) должен совпадать с CONCAT (x, y)

но помните, что:

  1. Список замены для CONCAT (x, y) - x ## y, и поскольку за x следует ##, а y предшествует ##, когда препроцессор видит экземпляр макроса CONCAT, он будет не расширяйте аргументы, которые соответствуют x или y перед заменой. Однако списком замены для CONCAT2 (x, y) является CONCAT (x, y), и ни x, ни y в замене не предшествуют # или ## или после ##, поэтому, когда препроцессор видит экземпляр макроса CONCAT2 , он расширит все макросы в аргументах ПОЛНОСТЬЮ ПЕРЕД заменой.

  2. Макро раскрытие аргументов (если разрешено) происходит ДО замены.Таким образом, в CONCAT2 (a, CONCAT (b, c)) аргумент CONCAT (b, c) раскрывается ДО замены.Таким образом, мы получаем CONCAT2 (a, b ## c), а не CONCAT (a, CONCAT (b, c)).

...