Препроцессор магии - PullRequest
       3

Препроцессор магии

3 голосов
/ 27 августа 2010

Я пытаюсь использовать приемы препроцессора для объявления магической переменной.Примерно так:

DECLARE(x)

должен расшириться до

int _DECLARED_VARIABLE_x_LINE_12

, если объявление было в строке 12 входного источника.Я пытался использовать команду ## token-pasteing и макрос __LINE__, но я либо получил неинтерпретированный «__LINE__», либо препроцессор, похоже, полностью игнорировал мою строку.Мое текущее предположение:

 #define DECLARE(x) _DECLARED_VARIABLE_ ## x ## _LINE_ ## __LINE__

Ответы [ 4 ]

9 голосов
/ 27 августа 2010

Обычный трюк в таких случаях - использовать второй макрос.Однако, похоже, что это не работает с GCC (4.5.1 в MacOS X 10.6.4), и необходим третий уровень макроса:

#define DECLARE(x) _DECLARED_VARIABLE_ ## x ## _LINE_ ## __LINE__

#define DECLARE42(x, line) _DECLARED_VARIABLE_ ## x ## _LINE_ ## line
#define DECLARE41(x, line) DECLARE42(x, line)
#define DECLARE40(x) DECLARE41(x, __LINE__)

int DECLARE(y);
int DECLARE40(c) = 129;

Вывод 'gcc -E':

# 1 "magicvars.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "magicvars.c"






int _DECLARED_VARIABLE_y_LINE___LINE__;
int _DECLARED_VARIABLE_c_LINE_8 = 129;

Я не уверен, что у меня есть хорошее объяснение того, почему был необходим третий уровень макроса.

Мне также любопытно узнать, как вы будете ссылаться на эти переменные послевы создали их.


Я прошел через несколько вариаций, прежде чем успел выбрать один из них:

#define DECLARE(x) _DECLARED_VARIABLE_ ## x ## _LINE_ ## __LINE__

#define DECLARE11(x, line) _DECLARED_VARIABLE_ ## x ## _LINE_ ## line
#define DECLARE10(x) DECLARE11(x, __LINE__)

#define DECLARE23(line) _LINE_ ## line
#define DECLARE22(x) _DECLARED_VARIABLE_ ## x
#define DECLARE21(x, line) DECLARE22(x) ## DECLARE23(line)
#define DECLARE20(x) DECLARE21(x, __LINE__)

#define DECLARE32(line) _LINE_ ## line
#define DECLARE31(x, line) _DECLARED_VARIABLE_ ## x ## DECLARE32(line)
#define DECLARE30(x) DECLARE31(x, __LINE__)

#define DECLARE42(x, line) _DECLARED_VARIABLE_ ## x ## _LINE_ ## line
#define DECLARE41(x, line) DECLARE42(x, line)
#define DECLARE40(x) DECLARE41(x, __LINE__)


int DECLARE(y);
int DECLARE10(z) = 12;
int DECLARE20(a) = 37;
int DECLARE30(b) = 91;
int DECLARE40(c) = 129;

Получайте удовольствие, выясняя, почему нерабочийодни не работали.Они, однако, указывают мне на рабочий ответ.(Я отмечаю, что компилятор Sun C выдает практически те же результаты, что и GCC на одном входе.)

6 голосов
/ 28 августа 2010

Препроцессор удаляет операторы ## из списка замены макросов перед тем, как попытается найти дополнительные макросы для рекурсивной замены.Это означает, что ваша ссылка на __LINE__ «приклеивается» к остальной части макроса до , она может быть распознана как __LINE__ и заменена фактическим номером строки.

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

#define DECLARE_(x, L) _DECLARED_VARIABLE_##x##_LINE_##L
#define DECLARE(x) DECLARE_(x, __LINE__)

И это формально решит непосредственную проблему в вашем оригиналеопределение макроса.

Однако это все равно не будет работать должным образом из-за еще одной особенности в спецификации препроцессора C / C ++: имена параметров, смежные с ##, заменяются соответствующими значениями аргументов без рекурсивное расширение макроса в значении аргумента.Т.е. L будет заменен на __LINE__, без замены __LINE__ на фактический номер строки первым.

Чтобы обеспечить рекурсивное расширение макроса для параметра L, необходимо ввести другой уровенькосвенность "в определении макроса

#define DECLARE__(x, L) _DECLARED_VARIABLE_##x##_LINE_##L
#define DECLARE_(x, L) DECLARE__(x, L)
#define DECLARE(x) DECLARE_(x, __LINE__)

В этом случае при обработке макроса DECLARE_(x, L) препроцессор будет обрабатывать L рекурсивно: сначала замените его на __LINE__, а затем замените __LINE__ на фактическоеномер строки.DECLARE__ получит полный номер строки.

1 голос
/ 27 августа 2010

Возникла проблема с __LINE__ в режиме отладки с Visual Studio, если вы использовали Edit и Continue. Вот ссылка на него. Этому вопросу уже несколько лет.Если эта проблема будет решена, решение Джонатана Леффлера будет работать нормально.

0 голосов
/ 31 августа 2010

В отношении оператора ## существуют два специальных правила расширения:

  1. Операнды оператора ## не вставляются перед вставкой.
  2. Аргументы макроса не раскрываются, если они соединяются с ##
...