Как преобразовать сцепленные строки в широкий символ с препроцессором C?

Я работаю над проектом, где у меня есть много постоянных строк, сформированных конкатенацией (числа, и т.д.).

Например, у меня есть a LOCATION макрос это форматирует __FILE__ и __LINE__ в строку, которую я могу использовать для знания, где я нахожусь в коде при печати сообщений или ошибок:

#define _STR(x)    # x
#define STR(x)     _STR(x)
#define LOCATION __FILE__ "(" STR(__LINE__) ")"

Так, это отформатировало бы местоположение как "file.cpp (42)". Проблема состоит в том, когда я пытаюсь преобразовать результат в широкую строку:

#define _WIDEN(x)  L ## x
#define WIDEN(x)   _WIDEN(x)
#define WLOCATION  WIDEN(LOCATION)

Это работает просто великолепно с GCC и приводит к L "file.cpp (42)" вставляемый в мой код. Однако при попытке этого MSVC ++ (использующий Экспресс Visual C++ 2008 года), я получаю ошибку:

error: Concatenating wide "file.cpp" with narrow "("

Я понимаю что L префикс добавляется только к первому сроку в моем выражении. Я также попробовал это:

#define _WIDEN(x) L ## #x

Который "работает", но дает строку L"\"file.cpp\" \"(\" \"42\" \")\"" который, очевидно, не очень удобен (и не, что я ищу), особенно полагая, что этот макрос прост по сравнению с другими макросами.

Так, мой вопрос: как я могу заставить это относиться ко всему выражению в MSVC ++, таким образом, я могу получить тот же результат, я добираюсь с GCC? Я не создал бы вторую строку со все-широкими маркерами, потому что я должен был бы затем поддержать два макросов для каждого, который не очень удобен и может привести к ошибкам. Плюс, мне нужна узкая версия каждой строки также, так использование все-широких строк не является опцией также, к сожалению.

7
задан Brian Tompsett - 汤莱恩 21 February 2016 в 14:19
поделиться

2 ответа

Согласно стандарту C (он же «ISO-9899: 1999» он же «C99») Visual C неверен, а gcc - правильно. Этот стандарт гласит, раздел 6.4.5 / 4:

На этапе перевода 6 многобайтовые последовательности символов, заданные любой последовательностью смежных символов и токенов литералов широкой строки, объединяются в одну многобайтовую последовательность символов. Если какой-либо из токенов является токенами широких строковых литералов, результирующая последовательность многобайтовых символов обрабатывается как широкие строковые литералы; в противном случае он рассматривается как литерал символьной строки.

Чтобы вы могли подать жалобу. Возможно, предыдущая версия стандарта C (он же «C89» или «C90» он же «ANSI C») не требовала объединения широких строк с неширокими строками. Хотя C99 сейчас более десяти лет, похоже, что Microsoft не заинтересована в том, чтобы сделать свой компилятор C совместимым. Некоторые пользователи сообщают, что могут получить доступ к некоторым функциям «C99» путем компиляции кода C, как если бы это был код C ++, потому что C ++ включает эти функции - а для C ++ Microsoft приложила усилия. Но, похоже, это не распространяется на препроцессор.

На диалекте C89 я думаю, что то, что вы ищете, невозможно (на самом деле я почти уверен в этом, и, поскольку я написал свой собственный препроцессор, я думаю, что знаю, о чем говорю). Но вы можете добавить дополнительный параметр и распространить его:

#define W(x)          W_(x)
#define W_(x)         L ## x
#define N(x)          x
#define STR(x, t)     STR_(x, t)
#define STR_(x, t)    t(#x)

#define LOCATION_(t)  t(__FILE__) t("(") STR(__LINE__, t) t(")")
#define LOCATION      LOCATION_(N)
#define WLOCATION     LOCATION_(W)

, который должен работать как с gcc, так и с Visual C (по крайней мере, он работает для меня, используя Visual C 2005).

Примечание: вы не должны определять макросы с именем, начинающимся с символа подчеркивания.Эти имена зарезервированы, поэтому при их использовании вы можете столкнуться с некоторыми именами, используемыми в системных заголовках или в будущих версиях компилятора. Вместо _WIDEN используйте WIDEN_ .

11
ответ дан 6 December 2019 в 19:36
поделиться

Для объединения двух широких буквенных строк можно было использовать

L"wide_a" L"wide_b"

, чтобы определить

#define WLOCATION WIDEN(__FILE__) L"(" WIDEN(STR(__LINE__)) L")"

(Примечание: не тестировалось на MSVC++)

.
1
ответ дан 6 December 2019 в 19:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: