Почему "#define WC (p) L # p" не работает в GCC и Clang?

Демо-программа:

#include <iostream>
using namespace std;

#define WC(p) L#p

int main()
{
 wcout << WC(XXX);
}
</iostream>

Он отлично работает на Visual C++, но не компилируется как на Clang, так и на GCC на Linux. Ошибки (clang 3.4, Linux):

  • file.cpp: 8: 11: ошибка: использование незаявленного идентификатора 'L'
  • file.cpp: 4: 15: примечание: расширено от макроса "WC"

Почему это терпит неудачу? Как создать строковый литерал с широким символом с помощью C определяет? Такая способность резко сократит дублирование кода в моем случае.

1 ответ

Препроцессор работает с последовательностью токенов.

В определении макроса WC(p) есть три токена в списке замещения: L, # и p. # - оператор, конечно, который "строит" следующий токен. Важно то, что L - это токен сам по себе. Результатом замены макроса на WC(XXX) является два токена: L и "XXX".

С другой стороны, широкий строковый литерал - это единственный токен. Независимо от написания списка замены макросов, два отдельных токена, где один является L а другой - узким строковым литералом, не являются широким строковым литералом. Это то же самое, что и L "XXX", с пробелом.

Вам нужно вставить вместе два токена в один токен, чтобы получить широкий строковый литерал. Это предлагает следующее решение:

#define WC(p) L ## #p

Изменить: Однако, как указано в комментариях, это может не сработать либо потому, что язык не гарантирует, что # будет оцениваться до ##. Нам нужно заставить препроцессор сначала преобразовать p в строку, а затем вставить маркеры:

#define CONCAT(x, y) x ## y
#define WC(p) CONCAT(L, #p)

Теперь WC(XXX) сначала подвергнется макрозаменке, чтобы получить CONCAT(L, "XXX"). Затем последующая макрозамена дает единственный токен L"XXX".

licensed under cc by-sa 3.0 with attribution.