关于已接受答案的一些评论位于本问题帖子的底部。
\n根据C标准(C17草案,6.10.3.2\xc2\xb62):
\n\n\n\n
#[the]和运算符的求值顺序##未指定。
我正在寻找一个示例,其中此评估顺序很重要,并且没有其他未定义行为的实例并且没有错误。
\n在花了一些时间处理这个问题之后,我怀疑以下方法可能有效:
\n#define PRECEDENCETEST(a, b, c) # a ## b\n\nPRECEDENCETEST(c, , d)\nRun Code Online (Sandbox Code Playgroud)\n(请注意,预处理器可以按如下方式运行:cpp或gcc -E(GCC),cl /E (MSVC);请参阅下面的可编译虚拟示例。另请注意,空宏参数仅自 C99 起才合法。)
我的问题:根据 C 标准,这实际上可以作为一个相对评估顺序#和产生合法输出的示例吗?##正如我在本文底部所解释的那样,如果我理解正确的话,答案可能取决于标准是否允许在之后使用令牌#与最初指定的令牌不同。
如果答案是“是(因为......)”,那么我们就找到了一个例子!如果答案是“不,你的例子不起作用(因为......)”,那么我稍后会想办法征求更好的例子。
\n(请注意,该标准不要求编译器对#和具有绝对相对评估顺序##运算符具有绝对相对的求值顺序。顺序可以是:从左到右、从右到左、遵循某些其他逻辑或完全随机。)
较旧的 GCC 文档(似乎最高版本为 6.5)指出:
\n\n
##该标准没有指定 \xe2\x80\x98 \xe2\x80\x99 运算符链的计算顺序,也没有#指定 \xe2\x80\x98 \xe2\x80\x99 …
c operator-precedence language-lawyer c-preprocessor token-pasting-operator
我正在编写自己的基于 GCC 的 C 预处理器。到目前为止,它几乎是相同的,但我认为多余的是对由 virue of 连接的令牌执行任何形式的检查##。所以在我的预处理器手册中,我写了这个:
3.5 串联
...
GCC 禁止连接两个互不兼容的预处理标记,例如“x”和“+”(以任何顺序)。这将导致以下错误:“粘贴“x”和“+”没有给出有效的预处理标记”但是对于这个预处理器来说这不是真的- 连接可能发生在任何标记之间。
我的推理很简单,如果它扩展为无效代码,那么编译器将产生错误,因此我不必显式处理此类情况,从而使预处理器变慢并增加代码复杂性。如果它产生了一个有效的代码,那么这个限制移除只会使它更灵活(尽管可能在极少数情况下)。
所以我想问一下,为什么这个错误真的发生了,为什么这个限制实际上被应用了,如果我在我的预处理器中忽略它是一种真正的犯罪吗?
c ×2