没有宏扩展的延迟字符串化

时间:2016-09-28 15:46:51

标签: c gcc macros c-preprocessor stringification

是否可以修改以下代码片段,以防止#pragma GCC warning打印的诊断在deprecation_message中的任何标识符令牌被定义为dmacro处的对象类宏时发生更改1}}是否已扩展,同时保留了将symbol替换为消息的能力? Ugliness没有对象,只要clang也实现它们,GCC扩展就是公平的游戏,但诊断的内容可能不会被修改。

#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 个答案:

答案 0 :(得分:2)

也许我误解了这个问题,但以下代码正在clanggcc上进行编译,并使用-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字符!