Есть ли способ написать шаблон макроса, который каким-то образом избегает расширения предварительного сканирования препроцессора? - PullRequest
0 голосов
/ 01 октября 2019

Мне интересно, существует ли шаблон записи макроса препроцессора, который может эффективно "пропустить" расширение макроса до сканирования.

#include <stdio.h>

#define SHIFT(label) label##_SHIFT
#define WIDTH(label) label##_WIDTH

#define MSB(label) label##_SHIFT + label##_WIDTH

#define A_SHIFT 0
#define A_WIDTH 4

#if 1
#define B_SHIFT 4
#else
/* Something like this would be preferred over, say
 * #define B_SHIFT A_SHIFT + A_WIDTH
 */
#define B_SHIFT MSB(A)  
#endif
#define B_WIDTH 4

int main(int argv, char ** argc) {
    (void)argv;
    (void)argc;

    (void)printf("A: Width %d\n", WIDTH(A));
    (void)printf("A: Shift %d\n", SHIFT(A));
    (void)printf("A: MSB   %d\n", MSB(A));

    (void)printf("B: Width %d\n", WIDTH(B));
    (void)printf("B: Shift %d\n", SHIFT(B));
    (void)printf("B: MSB   %d\n", MSB(B));
    return 0;
}

В надуманном примере выше, если вторая форма B_SHIFTиспользуется макрос, определение макроса при первом сканировании препроцессора хочет расширить A, что (конечно) не может.

Есть ли какая-то хитрость препроцессора, которая может быть использована для эффективного выполнения второй формы?

1 Ответ

0 голосов
/ 01 октября 2019

В приведенном выше надуманном примере, если используется вторая форма макроса B_SHIFT, определение макроса при первом сканировании препроцессора хочет расширить A, что (конечно) не может.

Проблема здесь в том, что вы организовали замену MSB(B) на себя, пытаясь выполнить подстановку MSB(A). Препроцессор C не допускает рекурсивной замены одного и того же макроса, даже в таких случаях, когда рекурсия полностью безопасна. В рамках подстановки макроса имя заменяемого макроса фактически не определено. Тот факт, что вы видите сообщение об ошибке, ссылающееся на A, является следствием того, что MSB(A) проходит через неизмененное, в результате чего и MSB, и A отображаются как токены после предварительной обработки. Поскольку ни один из них не был объявлен, компилятор жалуется на использование необъявленной функции (MSB) и переменной (A).

Одно простое (но явно не идеальное) исправление - использование двух идентичных макросов. определения:

#define SHIFT(label) label##_SHIFT
#define WIDTH(label) label##_WIDTH

#define MSB(label) label##_SHIFT + label##_WIDTH
#define MSB_(label) label##_SHIFT + label##_WIDTH

#define A_SHIFT 0
#define A_WIDTH 4
#define B_SHIFT MSB_(A)  
#define B_WIDTH 4

Это позволит расширить расширение B_SHIFT внутри расширения MSB(B).

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

...