为什么序列迭代在 C 宏中有效?

Why does sequence iteration work in C macro?

本文关键字:有效 迭代 为什么      更新时间:2023-10-16

在编写C宏时,有一个技巧叫做"序列迭代"。它看起来像下面:

#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
#define FUNCTION(name) void name();
#define FUNCTION_TABLE(seq) CAT(FUNCTION_TABLE_1 seq, _END)
#define FUNCTION_TABLE_1(x) FUNCTION(x) FUNCTION_TABLE_2
#define FUNCTION_TABLE_2(x) FUNCTION(x) FUNCTION_TABLE_1
#define FUNCTION_TABLE_1_END
#define FUNCTION_TABLE_2_END
FUNCTION_TABLE((x) (y) (z) (e))

序列,即FUCTION_TABLE的参数,将逐一处理。但是,据我所知,一个代币不会在同一范围内扩展两次。因为它是"涂成蓝色"的。展开FUNCTION_TABLE_2时,宏FUNCTION_TABLE_1已经绘制完毕。为什么还在扩容?

类似函数的宏替换是一个递归过程:

  • 宏首先以非递归方式扩展,除了###
  • 然后,递归地展开任何不是###操作数的令牌
  • ###(如果有)应用于生成的操作数
  • 转到 1,直到步骤 1-3 不会导致任何更改。

(这比实现要复杂一些!因此,对于您的代码:

  • FUNCTION_TABLE((x) (y) (z) (e))扩展到CAT(FUNCTION_TABLE_1 (x) (y) (z) (e), _END)
  • CAT(X, _END)扩展到PRIMITIVE_CAT(expand(X), _END)。现在expand(X)锻炼:
    • FUNCTION_TABLE_1 (x) (y) (z) (e)扩展到FUNCTION(x) FUNCTION_TABLE_2 (y) (z) (e)
      • FUNCTION(x)扩展到void x();
      • FUNCTION_TABLE_2 (y) (z) (e)扩展到FUNCTION(y) FUNCTION_TABLE_1 (z) (e)
      • FUNCTION(y)扩展到void y();
      • FUNCTION_TABLE_1 (z) (e)扩展到FUNCTION(z) FUNCTION_TABLE_2(e)
        • FUNCTION(z)扩展到void z();
        • FUNCTION_TABLE_2(e)扩展到FUNCTION(e) FUNCTION_TABLE_1
        • FUNCTION(e)扩展到void e();
        • 结果:void e(); FUNCTION_TABLE_1
        • 结果:void z(); void e(); FUNCTION_TABLE_1
      • 结果:void y(); void z(); void e(); FUNCTION_TABLE_1
      • 结果:void x(); void y(); void z(); void e(); FUNCTION_TABLE_1
  • 因此,完全扩展X,让我们回顾一下我们所处的位置:PRIMITIVE_CAT(void x(); void y(); void z(); void e(); FUNCTION_TABLE_1, _END)
  • 这扩展到void x(); void y(); void z(); void e(); FUNCTION_TABLE_1_END
  • 重新扫描后,这会产生void x(); void y(); void z(); void e();

这个想法是,在宏扩展中,所有参数的扩展都将以相同的 BLUE-SET 开始。

FUNCTION_TABLE(seq)内部FUNCTION_TABLE_1 seq内所有参数的扩展将始终以 BLUE-SET={seq} 开始。因此,进入FUNCTION_TABLE_1后,BLUE-SET 将添加x,但是当此操作完成后,它又回到了FUNCTION_TABLE的范围,其中扩展再次从BLUE-SET={seq}开始。

因此,第一次FUNCTION_TABLE_1(x)扩展时,在此扩展中BLUE-SET={seq,x}但是当FUNCTION_TABLE_1的扩展结束时,它会返回到FUNCTION_TABLE,并且接下来将从此范围扩展FUNCTION_TABLE_2(y)和内部FUNCTION_TABLE_2BLUE-SET={seq, x} 再次,依此类推。