gpt4 book ai didi

c - 类函数宏的扩展创建一个单独的标记

转载 作者:太空狗 更新时间:2023-10-29 17:13:15 26 4
gpt4 key购买 nike

我刚刚发现 gcc 似乎将类函数宏的扩展结果视为单独的标记。这是一个显示 gcc 行为的简单示例:

#define f() foo
void f()_bar(void);
void f()bar(void);
void f()-bar(void);

当我执行 gcc -E -P test.c(只运行预处理器)时,我得到以下输出:

void foo _bar(void);
void foo bar(void);
void foo-bar(void);

看起来,在前两个定义中,gcc 在扩展宏之后插入空格以确保它是一个单独的标记。这真的是这里发生的事情吗?

这是由任何标准强制执行的吗(我找不到关于该主题的文档)?

我想让 _bar 成为同一个标记的一部分。有什么办法吗?我可以使用 token 连接运算符 ## 但它需要多个级别的宏(因为在实际代码中 f() 更复杂)。我想知道是否有一个简单(并且可能更易读)的解决方案。

最佳答案

看起来,在前两个定义中,gcc 在扩展宏之后插入空格以确保它是一个单独的标记。这真的是这里发生的事情吗?

是的。

这是由任何标准强制执行的吗(我找不到关于该主题的文档)?

是的,尽管允许一个实现插入多个空格来分隔标记。

f()_bar

经过词法分析后,这里有 4 个标记(在这个阶段它们实际上是预处理器标记,但我们称它们为标记):f, (, )_bar

类似函数的宏替换语义(如 C11,6.10.3 中所定义)必须替换 3 个标记 f() 变成一个新的 foo。不允许对其他 token 进行操作并更改最后一个 _bar token 。为此,实现必须插入至少一个空格以保留 _bar 标记。否则结果将是 foo_bar,它是一个标记。

gcc 预处理器有点 documents它在这里:

Once the input file is broken into tokens, the token boundaries never change, except when the ‘##’ preprocessing operator is used to paste tokens together. See Concatenation. For example,

#define foo() bar
foo()baz
==> bar baz
not
==> barbaz

在另一种情况下,比如f()-bar,有5个标记:f, (, )-bar。 (- 是 C 中的标点符号,而 _bar 中的 _ 只是标识符 token 的一个字符)。该实现不必在此处插入标记分隔符(如空格),因为在宏替换后 -bar 仍被视为 C 语法中的两个单独标记。

gcc 预处理器 (cpp) 不会在此处插入空格,因为它不必这样做。在 cpp documentation ,关于标记间距,它是这样写的(在不同的问题上):

However, we would like to keep space insertion to a minimum, both for aesthetic reasons and because it causes problems for people who still try to abuse the preprocessor for things like Fortran source and Makefiles.

我没有在这个答案中解决您问题的解决方案,但我认为您必须使用明确指定的运算符来连接标记:## 标记粘贴运算符。

关于c - 类函数宏的扩展创建一个单独的标记,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32207668/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com