有没有一种方法可以编写可以避免预处理器预扫描扩展的宏模式?

时间:2019-10-01 16:52:20

标签: macros c-preprocessor

我想知道是否存在一种编写预处理程序宏的模式,可以有效地“跳过”预扫描宏扩展。

#include <stdio.h>

#define SHIFT(label) label##_SHIFT
#define WIDTH(label) label##_WIDTH

#define MSB(label) label##_SHIFT + label##_WIDTH

#define A_SHIFT 0
#define A_WIDTH 4

#if 1
#define B_SHIFT 4
#else
/* Something like this would be preferred over, say
 * #define B_SHIFT A_SHIFT + A_WIDTH
 */
#define B_SHIFT MSB(A)  
#endif
#define B_WIDTH 4

int main(int argv, char ** argc) {
    (void)argv;
    (void)argc;

    (void)printf("A: Width %d\n", WIDTH(A));
    (void)printf("A: Shift %d\n", SHIFT(A));
    (void)printf("A: MSB   %d\n", MSB(A));

    (void)printf("B: Width %d\n", WIDTH(B));
    (void)printf("B: Shift %d\n", SHIFT(B));
    (void)printf("B: MSB   %d\n", MSB(B));
    return 0;
}

在上述人为的示例中,如果使用B_SHIFT宏的第二种形式,则在预处理程序的第一次扫描中的宏定义要扩展A,(当然)它可以没错

是否可以使用一些预处理器技巧,以便可以有效地进行第二种形式?

1 个答案:

答案 0 :(得分:0)

  

在上面人为设计的示例中,如果使用B_SHIFT宏的第二种形式,则在预处理器的第一次扫描中的宏定义想要扩展A,(当然)不能。

这里的问题是,您已经安排将MSB(B)替换成它自己,以尝试进行MSB(A)替换。 C预处理器不允许递归替换同一宏,即使在这种情况下递归完全安全的情况下也是如此。在宏替换中,要替换的宏的名称实际上是未定义的。您看到指向A的错误消息的事实是MSB(A)未经更改地传递的结果,导致MSBA都在预处理后显示为标记。由于都未声明,因此编译器会抱怨使用未声明的函数(MSB)和变量(A)。

一个简单(但显然不理想)的修复方法是使用两个相同的宏定义:

#define SHIFT(label) label##_SHIFT
#define WIDTH(label) label##_WIDTH

#define MSB(label) label##_SHIFT + label##_WIDTH
#define MSB_(label) label##_SHIFT + label##_WIDTH

#define A_SHIFT 0
#define A_WIDTH 4
#define B_SHIFT MSB_(A)  
#define B_WIDTH 4

这将允许将B_SHIFT的扩展扩展为MSB(B)的扩展。

如果要查看其他解决方案可能是什么样,可以查看Boost Preprocessor library