我想强制预处理器为我进行一些自动代码生成。 我不需要很多:只需要一个包含另一个for循环的简单for循环。
我已经阅读了所有有关宏展开的内容,现在即使蓝色颜料出现时也不再发笑。 在好的日子里,我甚至可以解释为什么需要多层宏来生成带有标记粘贴的函数名称。 我实际上已经让for循环工作了。 但是当涉及到将一个循环嵌套在另一个循环中时,我就只能随机地使用DEFER、EVAL和OBSTRUCT并希望能得到最佳结果。
我不会因理性的呼吁而退缩。 我真的想使用标准的C预处理器来做到这一点。 我保证,无论结果如何,我、我的雇主和我的继承人都不会因技术过错而起诉您。 我保证,除非佩戴适当的安全眼镜,否则我不会允许任何其他人维护代码,甚至查看代码。 如果您愿意,可以假装我只是出于理论兴趣而提问。 或者,如果CPP中的递归宏很古怪,那么M4肯定是整个鸡。
我找到的最好的参考资料是一个9年前的Usenet主题讨论: http://comp.std.c.narkive.com/5WbJfCof/double-cpp-expansion 它开始离题,语气有些小气和挑衅,而且超出了我的理解范围。但我认为我寻找的答案在其中某个地方。
其次是一份名为Cloak的CPP滥用头文件的文档: https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms 它采用了一种略微不同的迭代方法,也许可以替代我所需的方法。但它也是一个很好的概述。
以下是一些简化的代码,以展示我卡住的地方。
在
实际上,如果我将块用作外层循环体,则可以使事情正常运行,但如果我使用类似函数的宏,则无法正常工作。但我需要使用带有参数的宏,以便循环体可以将循环计数器用作常量而不是变量。
“宏”-“宏”的问题在于对REPEAT_ADD_ONE()的内部递归调用没有展开。答案似乎是推迟内部循环的扩展,直到创建外部循环,然后强制进行另一次通过以扩展内部循环。但由于某种原因,我的“随机猴子”方法尚未产生解决方案……
[1]故意轻描淡写。
我已经阅读了所有有关宏展开的内容,现在即使蓝色颜料出现时也不再发笑。 在好的日子里,我甚至可以解释为什么需要多层宏来生成带有标记粘贴的函数名称。 我实际上已经让for循环工作了。 但是当涉及到将一个循环嵌套在另一个循环中时,我就只能随机地使用DEFER、EVAL和OBSTRUCT并希望能得到最佳结果。
我不会因理性的呼吁而退缩。 我真的想使用标准的C预处理器来做到这一点。 我保证,无论结果如何,我、我的雇主和我的继承人都不会因技术过错而起诉您。 我保证,除非佩戴适当的安全眼镜,否则我不会允许任何其他人维护代码,甚至查看代码。 如果您愿意,可以假装我只是出于理论兴趣而提问。 或者,如果CPP中的递归宏很古怪,那么M4肯定是整个鸡。
我找到的最好的参考资料是一个9年前的Usenet主题讨论: http://comp.std.c.narkive.com/5WbJfCof/double-cpp-expansion 它开始离题,语气有些小气和挑衅,而且超出了我的理解范围。但我认为我寻找的答案在其中某个地方。
其次是一份名为Cloak的CPP滥用头文件的文档: https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms 它采用了一种略微不同的迭代方法,也许可以替代我所需的方法。但它也是一个很好的概述。
以下是一些简化的代码,以展示我卡住的地方。
repeat.h:
#define REPEAT(macro, times, start_n, next_func, next_arg, macro_args...) \
_REPEAT_ ## times(macro, start_n, next_func, next_arg, ## macro_args)
#define REPEAT_ADD_ONE(macro, times, start_n, macro_args... ) \
REPEAT(macro, times, start_n, _REPEAT_ADD_ONE, 0, ## macro_args)
#define _REPEAT_ADD_ONE(n, ignore...) _REPEAT_ADD_ONE_ ## n
#define _REPEAT_0(args...) /* empty */
#define _REPEAT_1(macro, n, func, i, args...) macro(n, ## args)
#define _REPEAT_2(m, n, f, i, a...) m(n, ## a); _REPEAT_1(m, f(n, i), f, i, ## a)
#define _REPEAT_3(m, n, f, i, a...) m(n, ## a); _REPEAT_2(m, f(n, i), f, i, ## a)
#define _REPEAT_4(m, n, f, i, a...) m(n, ## a); _REPEAT_3(m, f(n, i), f, i, ## a)
#define _REPEAT_5(m, n, f, i, a...) m(n, ## a); _REPEAT_4(m, f(n, i), f, i, ## a)
#define _REPEAT_6(m, n, f, i, a...) m(n, ## a); _REPEAT_5(m, f(n, i), f, i, ## a)
#define _REPEAT_7(m, n, f, i, a...) m(n, ## a); _REPEAT_6(m, f(n, i), f, i, ## a)
#define _REPEAT_8(m, n, f, i, a...) m(n, ## a); _REPEAT_7(m, f(n, i), f, i, ## a)
#define _REPEAT_9(m, n, f, i, a...) m(n, ## a); _REPEAT_8(m, f(n, i), f, i, ## a)
#define _REPEAT_10(m, n, f, i, a...) m(n, ## a); _REPEAT_9(m, f(n, i), f, i, ## a)
#define _REPEAT_ADD_ONE_0 1
#define _REPEAT_ADD_ONE_1 2
#define _REPEAT_ADD_ONE_2 3
#define _REPEAT_ADD_ONE_3 4
#define _REPEAT_ADD_ONE_4 5
#define _REPEAT_ADD_ONE_5 6
#define _REPEAT_ADD_ONE_6 7
#define _REPEAT_ADD_ONE_7 8
#define _REPEAT_ADD_ONE_8 9
#define _REPEAT_ADD_ONE_9 10
#define _REPEAT_ADD_ONE_10 11
#define _REPEAT_ADD_0(x) x
#define _REPEAT_ADD_1(x) _REPEAT_ADD_ONE(x)
#define _REPEAT_ADD_2(x) _REPEAT_ADD_1(_REPEAT_ADD_ONE(x))
#define _REPEAT_ADD_3(x) _REPEAT_ADD_2(_REPEAT_ADD_ONE(x))
#define _REPEAT_ADD_4(x) _REPEAT_ADD_3(_REPEAT_ADD_ONE(x))
#define _REPEAT_ADD_5(x) _REPEAT_ADD_4(_REPEAT_ADD_ONE(x))
#define _REPEAT_ADD_6(x) _REPEAT_ADD_5(_REPEAT_ADD_ONE(x))
#define _REPEAT_ADD_7(x) _REPEAT_ADD_6(_REPEAT_ADD_ONE(x))
#define _REPEAT_ADD_8(x) _REPEAT_ADD_7(_REPEAT_ADD_ONE(x))
#define _REPEAT_ADD_9(x) _REPEAT_ADD_8(_REPEAT_ADD_ONE(x))
#define _REPEAT_ADD_10(x) _REPEAT_ADD_9(_REPEAT_ADD_ONE(x))
sample.c:
#include "repeat.h"
#define INNER_MACRO(inner, outer) if (inner == outer) printf("Match\n")
#define INNER_BLOCK { if (inner == outer) printf("Match\n"); }
#define OUTER_MACRO_INNER_MACRO(outer) REPEAT_ADD_ONE(INNER_MACRO, 3, 0, outer)
#define OUTER_BLOCK_INNER_MACRO { REPEAT_ADD_ONE(INNER_MACRO, 3, 0, outer); }
#define OUTER_MACRO_INNER_BLOCK(outer) REPEAT_ADD_ONE(INNER_BLOCK, 3, 0, outer)
#define OUTER_BLOCK_INNER_BLOCK { REPEAT_ADD_ONE(INNER_BLOCK, 3, 0, outer); }
void outer_macro_inner_macro() {
REPEAT_ADD_ONE(OUTER_MACRO_INNER_MACRO, 2, 1);
}
void outer_macro_inner_block() {
REPEAT_ADD_ONE(OUTER_MACRO_INNER_BLOCK, 2, 1);
}
void outer_block_inner_macro() {
REPEAT_ADD_ONE(OUTER_BLOCK_INNER_MACRO, 2, 1);
}
void outer_block_inner_block() {
REPEAT_ADD_ONE(OUTER_BLOCK_INNER_BLOCK, 2, 1);
}
在
sample.c
中,我展示了四种接近我想要的变体。但是没有一个完全符合要求。这是我使用"cpp sample.c > out.c; astyle out.c;"命令输出的结果。void outer_macro_inner_macro() {
REPEAT_ADD_ONE(INNER_MACRO, 3, 0, 1);
REPEAT_ADD_ONE(INNER_MACRO, 3, 0, 2);
}
void outer_macro_inner_block() {
REPEAT_ADD_ONE({ if (inner == outer) printf("Match\n"); }, 3, 0, 1);
REPEAT_ADD_ONE({ if (inner == outer) printf("Match\n"); }, 3, 0, 2);
}
void outer_block_inner_macro() {
{
if (0 == outer) printf("Match\n");
if (1 == outer) printf("Match\n");
if (2 == outer) printf("Match\n");
}(1);
{
if (0 == outer) printf("Match\n");
if (1 == outer) printf("Match\n");
if (2 == outer) printf("Match\n");
}(2);
}
void outer_block_inner_block() {
{ {
if (inner == outer) printf("Match\n");
}(0, outer);
{
if (inner == outer) printf("Match\n");
}(1, outer);
{
if (inner == outer) printf("Match\n");
}(2, outer);
}(1);
{ {
if (inner == outer) printf("Match\n");
}(0, outer);
{
if (inner == outer) printf("Match\n");
}(1, outer);
{
if (inner == outer) printf("Match\n");
}(2, outer);
}(2);
}
这里是我想要得到的输出:
void desired_results() {
{
if (0 == 1) printf("Match\n");
if (1 == 1) printf("Match\n");
if (2 == 1) printf("Match\n");
};
{
if (0 == 2) printf("Match\n");
if (1 == 2) printf("Match\n");
if (2 == 2) printf("Match\n");
};
}
实际上,如果我将块用作外层循环体,则可以使事情正常运行,但如果我使用类似函数的宏,则无法正常工作。但我需要使用带有参数的宏,以便循环体可以将循环计数器用作常量而不是变量。
“宏”-“宏”的问题在于对REPEAT_ADD_ONE()的内部递归调用没有展开。答案似乎是推迟内部循环的扩展,直到创建外部循环,然后强制进行另一次通过以扩展内部循环。但由于某种原因,我的“随机猴子”方法尚未产生解决方案……
[1]故意轻描淡写。