我想知道是否存在一种编写预处理程序宏的模式,可以有效地“跳过”预扫描宏扩展。
#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
,(当然)它可以没错
是否可以使用一些预处理器技巧,以便可以有效地进行第二种形式?
答案 0 :(得分:0)
在上面人为设计的示例中,如果使用B_SHIFT宏的第二种形式,则在预处理器的第一次扫描中的宏定义想要扩展A,(当然)不能。
这里的问题是,您已经安排将MSB(B)
替换成它自己,以尝试进行MSB(A)
替换。 C预处理器不允许递归替换同一宏,即使在这种情况下递归完全安全的情况下也是如此。在宏替换中,要替换的宏的名称实际上是未定义的。您看到指向A
的错误消息的事实是MSB(A)
未经更改地传递的结果,导致MSB
和A
都在预处理后显示为标记。由于都未声明,因此编译器会抱怨使用未声明的函数(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。