有没有一种方法可以编写以某种方式避免预处理器预扫描扩展的宏模式?
Is there a way to write a macro pattern that somehow avoids preprocessor prescan expansion?
我想知道是否存在一种编写预处理器宏的模式可以有效地 "skip" 预扫描宏扩展。
#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
,这(当然)它不能。
是否可以使用一些预处理器技巧来有效地执行第二种形式?
In the contrived example above, if the second form of the B_SHIFT macro is used, the macro definition in the first scan of the preprocessor wants to expand A, which (of course) it can't.
这里的问题是,您已经安排了 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。
我想知道是否存在一种编写预处理器宏的模式可以有效地 "skip" 预扫描宏扩展。
#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
,这(当然)它不能。
是否可以使用一些预处理器技巧来有效地执行第二种形式?
In the contrived example above, if the second form of the B_SHIFT macro is used, the macro definition in the first scan of the preprocessor wants to expand A, which (of course) it can't.
这里的问题是,您已经安排了 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。