2016-09-28 4 views
1

Можно ли изменить следующий фрагмент кода, чтобы предотвратить изменение диагностической информации, напечатанной #pragma GCC warning, если какой-либо токен идентификатора в deprecation_message определен как макрос объектов в точке, где dmacro расширен, тогда как сохраняя возможность вносить в сообщение symbol? Ugliness no object, расширения 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") является синтаксической ошибкой)

ответ

2

Может быть, я неправильно понял вопрос, но следующий код работает и компиляция на обоих 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); 
      ^~~~~~~~ 

В основном все Я сделал это, чтобы положить сообщение об отказе в кавычки ...


UPDATE :

Теперь, забавная вещь, если вы удалите stringification из 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); 
    ^

Wh Ich хорошо, так как он не имеет нежелательных кавычки, однако GCC только даст вам:

src/main.c:18:13: warning: dmacro 
    dmacro(x, y, z); 
      ^~~~~~~~ 

Что еще более странно, что если изменить deprecation_message к этому:

#define deprecation_message(symbol) "" #symbol "..." 

, то это даст вам пустое предупреждение, так как оно использовало только первый маркер небелого пространства из аргумента макроса.

Чтобы быть честным с вами, я не знаю, является ли это ошибкой от GCC, или это четко определенное поведение, и clang делает дополнительную работу, чтобы иметь смысл из этого, тем не менее, это происходит с последними версиями двух компиляторов.(Если я должен держать пари, я бы сказал, что это ошибка: P)


UPDATE :

Вот слегка измененная версия, которая работает на обоих компиляторов как вы описали в своем комментарии. Фокус в том, что макрос 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 из вашего сообщения!

+0

Мне придется делать некоторые эксперименты вокруг этой очевидной ошибки самостоятельно, но прямо сейчас, просто чтобы быть ясным, когда я сказал, что «содержимое диагностики не может быть изменено», я хотел исключить все, что добавили бы дополнительные кавычки в вывод компилятора. – zwol

+0

@zwol Я обновил свой ответ, теперь все ненужные цитаты исчезли, и он работает над обоими компиляторами! –

+2

О, это умно. Сначала я не видел трюка. – zwol

Смежные вопросы