Задержка строкового преобразования без расширения макроса
Можно ли изменить следующий фрагмент кода, чтобы предотвратить печать #pragma GCC warning
от изменения, если какой-либо из токенов идентификатора в deprecation_message
определяются как объектно-подобные макросы в точке, где dmacro
расширяется, сохраняя при этом возможность замены symbol
в сообщение? Уродство - не объект, расширения GCC - честная игра, если только clang их реализует, но содержание диагностики не может быть изменено.
#define deprecation_message(symbol) \
#symbol will be removed from <header.h> in the next release\n\
of $LIBRARY. To use #symbol, include <moved/header.h> instead.
#define make_pw(...) make_pw_(__VA_ARGS__)
#define make_pw_(...) make_pw__(GCC warning #__VA_ARGS__)
#define make_pw__(...) _Pragma(#__VA_ARGS_)
#define dmacro(a,b,c) make_pw(deprecation_message(dmacro)) xmacro(a,b,c)
// Uncommenting any of the following #define lines should *not*
// change the text of the diagnostic in any way.
//#define header
//#define n f
//#define will won't'
dmacro(x,y,z)
(Вы можете испытать желание достичь конкатенации строкового литерала, но это не сработает; оба _Pragma
сам и #pragma GCC warning
принимать только один строковый литерал. _Pragma("this" "that")
это синтаксическая ошибка.)
1 ответ
Может быть, я неправильно понял вопрос, но следующий код работает и компилирует оба clang
а также gcc
и протестирован с -std=c99
а также -std=c11
:
#include <stdio.h>
#include <stdlib.h>
#define deprecation_message(symbol) \
#symbol " will be removed from <header.h> in the next release\n" \
"of $LIBRARY. To use " #symbol ", include <moved/header.h> instead."
#define make_pw__(...) _Pragma(#__VA_ARGS__)
#define make_pw_(...) make_pw__(GCC warning #__VA_ARGS__)
#define make_pw(...) make_pw_(__VA_ARGS__)
#define xmacro(a, b, c) puts("I'm working: " #a #b #c "!")
#define dmacro(a, b, c) make_pw(deprecation_message(dmacro)) xmacro(a, b, c)
int
main(void)
{
dmacro(x, y, z);
return EXIT_SUCCESS;
}
Теперь приведенный выше код расширит это с clang
:
int
main(void)
{
#pragma GCC warning "\042dmacro\042 \042 will be removed from <header.h> in the next release\134n\042 \042of $LIBRARY. To use \042 \042dmacro\042 \042, include <moved/header.h> instead.\042"
puts("I'm working: " "x" "y" "z" "!");
return 0 /* Successful exit status. */;
}
и выдаст следующие предупреждения clang
:
src/main.c:18:5: warning: "dmacro" " will be removed from <header.h> in the next release\n" "of $LIBRARY. To use " "dmacro" ", include <moved/header.h> instead." [-W#pragma-messages]
dmacro(x, y, z);
^
и это на gcc
:
src/main.c:18:13: warning: "dmacro" " will be removed from <header.h> in the next release\n" "of $LIBRARY. To use " "dmacro" ", include <moved/header.h> instead."
dmacro(x, y, z);
^~~~~~~~
По сути, все, что я сделал, это поместил сообщение об устаревании в кавычки...
ОБНОВЛЕНИЕ1:
Теперь самое смешное, если вы удалите make_pw_
, то есть:
#define make_pw_(...) make_pw__(GCC warning __VA_ARGS__)
затем clang
даст вам это:
src/main.c:18:5: warning: dmacro will be removed from <header.h> in the next releaseof $LIBRARY. To use dmacro, include <moved/header.h> instead. [-W#pragma-messages]
dmacro(x, y, z);
^
Что приятно, так как не содержит нежелательных цитат, однако GCC
только даст вам это:
src/main.c:18:13: warning: dmacro
dmacro(x, y, z);
^~~~~~~~
Что еще более странно, это то, что если вы измените deprecation_message
к этому:
#define deprecation_message(symbol) "" #symbol "..."
тогда он выдаст пустое предупреждение, как если бы он использовал только первый токен без пробелов из аргумента макроса.
Если честно, я не знаю, является ли это ошибкой GCC
или это четко определенное поведение и clang
делает некоторую дополнительную работу, чтобы разобраться в этом, тем не менее, это происходит с последними версиями двух компиляторов. (Если бы мне пришлось делать ставку, я бы сказал, это ошибка:P)
ОБНОВЛЕНИЕ2:
Вот немного измененная версия, которая работает на обоих компиляторах, как вы описали в своем комментарии. Хитрость в том, что макрос DEPRECATED
имеет два этапа вместо одного.
#include <stdio.h>
#include <stdlib.h>
#define DEPRECATED_(...) #__VA_ARGS__
#define DEPRECATED(symbol) \
DEPRECATED_(#symbol will be removed from <header.h> in the next release\n \
of $LIBRARY. To use #symbol, include <moved/header.h> instead.)
#define PRAGMA_WARN_(message) _Pragma(#message)
#define PRAGMA_WARN(message) PRAGMA_WARN_(GCC warning message)
#define dmacro(a, b, c) \
PRAGMA_WARN(DEPRECATED(dmacro)) \
puts("I'm working: " #a #b #c "!")
int
main(void)
{
dmacro(x, y, z);
return EXIT_SUCCESS;
}
Так что это даст следующий результат в clang
:
src/main.c:19:5: warning: "dmacro" will be removed from <header.h> in the next release of $LIBRARY. To use "dmacro", include <moved/header.h> instead. [-W#pragma-messages]
dmacro(x, y, z);
^
И следующий в GCC
:
src/main.c:19:13: warning: "dmacro" will be removed from <header.h> in the next release
of $LIBRARY. To use "dmacro", include <moved/header.h> instead.
dmacro(x, y, z);
^~~~~~~~
ПРИМЕЧАНИЕ: я настоятельно рекомендую вам удалить\n
персонаж из вашего сообщения!