3

我对使用取消引用运算符进行预处理器粘贴的“##”有疑问。谁能告诉我为什么下面的代码无法编译?

typedef struct
{
    char data;
} MY_STRUCT;

MY_STRUCT  My_Instance;
MY_STRUCT* My_PInstance;

#if 1
#define GET_MEMBER(membername)         (My_PInstance->##membername)
#else
#define GET_MEMBER(membername)         (My_Instance.##membername)
#endif

然后当我打电话时:

char value = GET_MEMBER(data);  // Where My_PInstance is properly instantiated.

我得到一个编译错误。

error: pasting "->" and "data" does not give a valid preprocessing token
4

2 回答 2

6

你不需要粘贴。做就是了(My_Pinstance->membername)

'##' 应该将两个标记粘贴到一个有效标记中。但是 ->foo不是有效的令牌。(例如,foo)

于 2012-12-05T02:39:08.837 回答
2

只为其他任何来这里的人。我遇到了同样的问题,但使用了“。” 未讨论的 GET_MEMBER(..) 宏的变体,但我认为问题是相同的。

我犹豫地接受了 cwyang 的回答,因为真正粘贴的是文本

My_PInstance->

data

根据我(和用户……)的想法,结果是一个适当的标记。

My_PInstance->data

所以,我坚持通过更多的谷歌结果。最终我找到了这个人,他给出了一个真正打击的历史记录。概括:

回到过去,存在一种古老的替代语法,但没有编译器再认识到这种胡说八道。甚至不要去那里。

男人。这家伙说没有希望了......

那么,到底是什么?我去了那儿。替代语法有效,我几乎没有使用古老的编译器!

g++ (GCC) 4.7.3
Copyright (C) 2012 Free Software Foundation, Inc.

所以,对于所有勇敢的字符串化器、连接器和标记器(!),这是我给你的教训。

前:

#define PROFILING_START_CLK(STAT, n)                        \
    time0##STAT##n = PRF_CLK_FN();                          \
    profilingStatsIndex##STAT##n = STAT##.count % PROFILE_SIZE; \
    STAT#.count++;

如此称呼:

PROFILING_START_CLK(tst, 0);

为使用它的每个地方返回 2 个以下错误实例:

error: pasting "tst" and "." does not give a valid preprocessing token

就像 user1159503 一样。

不过,继续前进.... 以下工作:

#define PROFILING_START_CLK(STAT, n)                          \
    time0##STAT##n = PRF_CLK_FN();                            \
    profilingStatsIndex##STAT##n = STAT/**/.count % PROFILE_SIZE;\
---------------------------------------^^^^
    STAT/**/.count++;
--------^^^^

无论我是否使用 g++ -ansi 开关,之前/之后的版本都失败/编译。

它起作用的原因是因为预处理器在进入宏之前会去除注释,所以顺序是这样的。

  1. 当 '/**/' 被剥离时,STAT 与 .count 邻接。
  2. 避免了“##”过程。特别是,在代码的这一点上避免了它对有效结果令牌的检查。
  3. STAT 被字符串化为“tst”(在我的例子中)
  4. 随后的解析/令牌检查发现“tst.count”非常合适和令人愉快。

'##' 是否应该在宏中组装任意结构和/或成员?我不知道。我会这么认为,但粘贴过程不跨越运算符似乎也是正确的。

否则,问题将是,“粘贴过程是否像我们在这里讨论的那样仅跨越“加入”运算符。('.','->','::',...)

于 2013-10-18T19:03:57.557 回答