Я компилирую следующий код C ++ в Visual Studio 2015 (обновление 3):
#include <iostream>
using namespace std;
////////////////////////////////////////
#define UNDERSCORE1(a,b) a ## _ ## b
#define UNDERSCORE(a,b) UNDERSCORE1(a,b)
#define STRINGIFY1(x) #x
#define STRINGIFY(x) STRINGIFY1(x)
#define VALUE(x) UNDERSCORE(x, VALUE)
#define NEXT(x) (VALUE(x) + 1)
/////////////////////////////////////////
#define X1_VALUE 0
#define X2_VALUE NEXT(X1)
#define X3_VALUE NEXT(X2)
#define TOTAL NEXT(X3)
int main() {
cout << STRINGIFY(TOTAL) << endl;
cout << TOTAL << endl;
return 0;
}
Результат, выводимый на стандартный вывод, очень странный:
(X3_VALUE + 1)
3
При попыткето же самое для gcc, сборка завершается неудачно (как и ожидалось).
При комментировании cout << TOTAL << endl;
я получаю что-то совсем другое в целом:
(NEXT(X2) + 1)
На самом деле поведение gcc имеет смысл, посколькуМакрос NEXT
вызывается рекурсивно: NEXT(X3)
расширяется до X3_VALUE
, который, в свою очередь, расширяется до NEXT(X2)
, поэтому второе расширение макроса NEXT
(NEXT(X2)
) не выполняется.
Что не имеет смысла, так это поведение Visual Studio:
- При печати макроса
TOTAL
с использованием STRINGIFY
, NEXT
кажется расширенным в два раза для получения X3_VALUE
. - При компиляции макроса
TOTAL
напрямую для отправки его в cout
, NEXT
полностью расширяется!Как будто препроцессор запускался несколько раз, чтобы рекурсивно развернуть NEXT
.
Еще одна вещь, которую я пытался скомпилировать в Visual Studio с опцией компилятора /P
, чтобы получить предварительно обработанный код:
int main() {
cout << "(X3_VALUE + 1)" << endl;
cout << (((0 + 1) + 1) + 1) << endl;
return 0;
}
- Так это, как я подозреваю, ошибка в препроцессоре Visual Studio?Или законное неопределенное поведение?
- Возможно, этим поведением можно злоупотребить, чтобы действительно рекурсивно расширить макросы?Я знаю, что ограниченная рекурсия возможна с некоторыми уловками , но ограничена заранее определенным числом сканирований.В этом случае я не наблюдал ограничения на количество раз,
NEXT
расширяется.