5

我有一个这样的宏(不完全是,但功能相当):

#define STRUCTMEMBER(Member,Value) GlobalStructInstance. ## Member = Value
...
STRUCTMEMBER(Item,1);

这在 Visual C++ 中完美运行,但 gcc 3.4.5 (MingGW) 产生以下错误:

粘贴“。” 并且“Item”没有给出有效的预处理令牌

当我使用“->”运算符时也会发生这种情况。我没有发现关于连接的提示,禁止使用这些运算符。

有人有想法吗?

4

3 回答 3

7

也许 Visual C++ 将几个空格粘贴在一起以形成另一个空格。并不是说空格是标记,而是它可以让你的代码工作。

object.member不是令牌,是三个令牌,所以你不需要令牌粘贴来实现你描述的宏。只需删除'##',它应该可以在任何地方工作。

[编辑:刚刚检查,使用 ## 形成不是有效令牌的结果是未定义的。因此,据我所知,允许 GCC 拒绝它,允许 MSVC 忽略它并且不执行粘贴。]

于 2009-07-30T13:41:18.073 回答
5

根据 C 标准,“ ##”预处理运算符的结果必须是“预处理标记”,否则结果未定义(C99 6.10.3.3(3) - ## 运算符)。

预处理标记的列表是(C99 6.4(3) - 词法元素):

标头名称、标识符、预处理数字、字符常量、字符串文字、标点符号和在词法上与其他预处理标记类别不匹配的单个非空白字符。

GCC 让您知道您正在进入未定义的领域。MSVC 对未定义的结果非常满意(这是您非常期望发生的)。

请注意,如果您无论如何都没有创建单个令牌,那么您不需要令牌粘贴运算符。通常(我确定可能有一两个例外),由空格分隔的 2 个标记等同于不由空格分隔的 2 个标记 - 如您的示例所示。

于 2009-07-30T14:25:11.857 回答
4

gcc c 预处理器文档

但是,不能将不一起形成有效令牌的两个令牌粘贴在一起。

structure.member 不是一个单一的标记。

在这种情况下,您不需要使用 ##(令牌连接)运算符。你可以删除它。这是在 linux 上使用 gcc 4.2.4 测试的示例:

#include <stdio.h>

#define STRUCTMEMBER(Member, Value) GlobalStructInstance.Member = Value

struct {
    const char* member1;
}GlobalStructInstance;

int main(void)
{

    STRUCTMEMBER(member1, "Hello!");

    printf("GlobalStructInstance.member1 = %s\n",
           GlobalStructInstance.member1);

    return 0;
}
于 2009-07-30T13:59:22.170 回答