【问题标题】:Double hash usage双哈希使用
【发布时间】:2020-09-22 13:30:18
【问题描述】:

在 C99 6.10.3.3.(2) 中(我的亮点)

如果在类函数宏的替换列表中,一个参数紧跟在前面 或后跟##预处理标记,参数替换为对应的 参数的预处理标记序列;但是,如果参数由 no 组成 预处理标记,该参数被替换为地标预处理标记

#include <stdio.h>
#define hash_hash(a, b) a ## b
#define mkstr(a) # a
#define in_between(a) mkstr(a)

void main(void)
{
    char p[] = in_between(a hash_hash(,) b);
    printf("%s", p);
}

输出:

a  b

我用hash_hash(,) 描述了突出显示的短语,结果似乎作为标准的表示是正确的。

但我想知道是否省略了逗号,,如hash_hash(),那么这与标准的解释不同(未定义的行为)吗? placemaker 和空格一样吗?

【问题讨论】:

    标签: c language-lawyer c-preprocessor


    【解决方案1】:

    但我想知道是否省略了逗号,例如 hash_hash(),那么这与标准的解释不同(未定义的行为)吗?

    我认为相关部分是 C11 6.10.3/4 强调我的:

    约束

    如果宏定义中的标识符列表不以省略号结尾,则调用类函数宏时的参数数量(包括那些不包含预处理标记的参数)等于宏定义中的参数个数。

    逗号会给出一个没有 pre-proc 标记的有效标识符列表,但没有它,标识符列表与宏的参数数量不匹配。所以 hash_hash() 是违反约束的,您应该收到一条诊断消息。

    【讨论】:

      【解决方案2】:

      但我想知道是否省略了逗号,,如hash_hash(),那么这与标准的解释不同(未定义的行为)吗?

      在这种情况下,逗号是类函数宏调用语法的一部分。它分隔宏的参数列表中的参数。类函数宏的调用必须为该宏的每个命名参数提供一个值,并且使用hash_hash()(不带逗号)您不会这样做。这将违反语言约束,因此不仅结果行为是未定义的,而且符合标准的 C 实现也有义务在遇到此类违反时发出诊断信息。

      placemaker 和空格一样吗?

      没有。您可以将地点标记概念化为长度为零的预处理标记。这样的事情不能直接在源代码中表示。它既不是空白也不是没有预处理标记。 “地标”很好地描述了它的性质和作用。

      【讨论】:

        【解决方案3】:

        如果省略逗号,,如hash_hash(),那么这与标准的解释不同(未定义的行为)吗? placemaker 和 white-space 一样吗?

        是的,如果宏定义了参数,参数必须用逗号分隔。否则尝试定义多参数宏将违反标准规则,并且无法编译:

        类似函数的宏可以接受参数,就像真正的函数一样。到 定义一个使用参数的宏,在 宏定义中构成宏的一对括号 函数式的。参数必须是有效的 C 标识符, 以逗号分隔和可选的空格。

        此外,

        • 因为此要求是well defined,所以它不是未定义行为的示例。
        • 在参考段落的这个短语中and 可选空格and表示空格可以是与分隔符一起使用,但仅作为分隔符是不够的。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-02-13
          • 2012-01-25
          • 2017-07-04
          • 1970-01-01
          • 2014-03-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多