提问人:morrantho 提问时间:1/31/2023 更新时间:2/3/2023 访问量:136
C - X 宏自迭代/扩展
C - X Macro Self Iteration / Expansion
问:
我很好奇你们中是否有人能想出一种宏扩展方法来重复宏本身。这是一个整体更大问题的令人难以置信的小规模版本:
#include<stdio.h>
#define LETTERS\
X(A)\
X(B)\
X(C)\
X(D)
#define X(L) #L
int main(int nargs,char** args)
{
printf("%s\n",LETTERS);
return 0;
}
输出: ABCD
期望输出:AABCD BABCD CABCD DABCD
所需的输出显然类似于任何输入数据上的嵌套 (N^2) 循环。
字符串化无关紧要,它仅用于编译。
对于所需的输出,有一些明显和一些不那么明显的解决方案。
一种是制作宏的完整副本,然后在每个 X 元素之间,您只需引用副本即可。这将是浪费,我不想这样做。显然,由于递归,您不能引用宏本身。我已经做了很多尝试来找到一个体面的解决方案,并且不会列出所有这些解决方案,因为这会占用太多时间。我对使用其他宏来重复或扩展原始宏的解决方案,或使用卡顿形式的递归的解决方案持开放态度。
#include<stdio.h>
#define LETTERS_COPY\
X(A)\
X(B)\
X(C)\
X(D)
#define LETTERS\
X(A)\
LETTERS_COPY\
X(B)\
LETTERS_COPY\
X(C)\
LETTERS_COPY\
X(D)\
LETTERS_COPY
#define X(L) #L
int main(int nargs,char** args)
{
printf("%s\n",LETTERS);
return 0;
}
同样,这构建得很好并且有效,但需要原始数据的完整副本,在每个 X 元素之间插入自己。
答:
对于任何想知道的人,我能做的最好的事情就是制作第二个需要 2 个参数的 X 宏,而外部列表变成一个需要单个参数的函数宏。这样一来,您就可以将数据传递到列表和第二个 x 宏,同时仍然能够根据需要解压缩任一 X 宏。
#include<stdio.h>
#define _CAT(A,B) A##B
#define CAT(A,B) _CAT(A,B)
#define _STR(S) #S
#define STR(S) _STR(S)
#define LETTERS(L)\
XX(L,X(A))\
XX(L,X(B))\
XX(L,X(C))\
XX(L,X(D))
int main(int nargs,char** args)
{
#define X(L) L
#define XX(L1,L2) STR(CAT(L1,L2))
printf("%s\n",LETTERS(A));
printf("%s\n",LETTERS(B));
printf("%s\n",LETTERS(C));
printf("%s\n",LETTERS(D));
#undef XX
#undef X
return 0;
}
如果使用迭代宏,就像在 P99 宏实用程序集合中定义宏一样,那么求解起来就会容易得多。
由于我们打算定义一个迭代宏,因此我们不再需要字母上的 X 宏。
#define LETTERS \
A \
,B \
,C \
,D
下面是一个简化的迭代宏,最多支持 5 个参数。如果您需要更多,希望您能看到如何扩展实现。
#define XX(X, ...) \
XX_X(__VA_ARGS__, XX_5, XX_4, XX_3, XX_2, XX_1) \
(X, __VA_ARGS__)
#define XX_X(_1,_2,_3,_4,_5,X,...) X
#define XX_1(X, _) X(_)
#define XX_2(X, _, ...) X(_) XX_1(X, __VA_ARGS__)
#define XX_3(X, _, ...) X(_) XX_2(X, __VA_ARGS__)
#define XX_4(X, _, ...) X(_) XX_3(X, __VA_ARGS__)
#define XX_5(X, _, ...) X(_) XX_4(X, __VA_ARGS__)
因此,如果您调用 ,它将扩展到您之前拥有的 X-macro 版本。XX(X, LETTERS)
LETTERS
宏的魔力在于宏的元性质,它选择正确的数字宏来使用。当 调用时,数字宏将以相反的顺序传递给宏。这样,如果包含较少的参数,则选择较低的数值宏。XX()
XX_X()
XX_X()
XX()
XX_X()
__VA_ARGS__
现在,我们创建一个宏来将参数转换为字符串:
#define STR(X) STR_(X)
#define STR_(X) #X
这使您可以轻松地创建包含所有字母的字符串。 打印迭代输出只需要另一个宏。
int main () {
const char *letters = XX(STR, LETTERS);
#define LETTERS_PRINT(X) printf("%s%s\n", #X, letters);
XX(LETTERS_PRINT, LETTERS)
}
我们看到该解决方案适用两次。一次创建所有字母的字符串。一次创建输出,该输出将每个字母添加到组合字母之前。XX()
上一个:在 X 宏 C 中定义相同的元素
评论
LETTERS