这是我今天的作业,它基于宏观技巧,今天我特别了解__VA_NARG__
了由 Laurent Deniau 发明的。无论如何,为了清楚起见,以下示例代码最多可以使用 8 个字段。如果您需要更多,只需通过复制来扩展代码(这是因为预处理器不具有递归功能,因为它只读取文件一次)。
#include <stdio.h>
#include <stddef.h>
struct a
{
int a;
int b;
int c;
};
struct b
{
int a;
int b;
int c;
int d;
};
#define STRINGIZE(arg) STRINGIZE1(arg)
#define STRINGIZE1(arg) STRINGIZE2(arg)
#define STRINGIZE2(arg) #arg
#define CONCATENATE(arg1, arg2) CONCATENATE1(arg1, arg2)
#define CONCATENATE1(arg1, arg2) CONCATENATE2(arg1, arg2)
#define CONCATENATE2(arg1, arg2) arg1##arg2
/* PRN_STRUCT_OFFSETS will print offset of each of the fields
within structure passed as the first argument.
*/
#define PRN_STRUCT_OFFSETS_1(structure, field, ...) printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d\n", offsetof(structure, field));
#define PRN_STRUCT_OFFSETS_2(structure, field, ...)\
printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d\n", offsetof(structure, field));\
PRN_STRUCT_OFFSETS_1(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_3(structure, field, ...)\
printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d\n", offsetof(structure, field));\
PRN_STRUCT_OFFSETS_2(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_4(structure, field, ...)\
printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d\n", offsetof(structure, field));\
PRN_STRUCT_OFFSETS_3(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_5(structure, field, ...)\
printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d\n", offsetof(structure, field));\
PRN_STRUCT_OFFSETS_4(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_6(structure, field, ...)\
printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d\n", offsetof(structure, field));\
PRN_STRUCT_OFFSETS_5(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_7(structure, field, ...)\
printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d\n", offsetof(structure, field));\
PRN_STRUCT_OFFSETS_6(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_8(structure, field, ...)\
printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d\n", offsetof(structure, field));\
PRN_STRUCT_OFFSETS_7(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_NARG(...) PRN_STRUCT_OFFSETS_NARG_(__VA_ARGS__, PRN_STRUCT_OFFSETS_RSEQ_N())
#define PRN_STRUCT_OFFSETS_NARG_(...) PRN_STRUCT_OFFSETS_ARG_N(__VA_ARGS__)
#define PRN_STRUCT_OFFSETS_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
#define PRN_STRUCT_OFFSETS_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0
#define PRN_STRUCT_OFFSETS_(N, structure, field, ...) CONCATENATE(PRN_STRUCT_OFFSETS_, N)(structure, field, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS(structure, field, ...) PRN_STRUCT_OFFSETS_(PRN_STRUCT_OFFSETS_NARG(field, __VA_ARGS__), structure, field, __VA_ARGS__)
int main(int argc, char *argv[])
{
PRN_STRUCT_OFFSETS(struct a, a, b, c);
printf("\n");
PRN_STRUCT_OFFSETS(struct b, a, b, c, d);
return 0;
}
打印出来:
struct a:a-0
struct a:b-4
struct a:c-8
struct b:a-0
struct b:b-4
struct b:c-8
struct b:d-12
编辑:这是一个稍微不同的版本,它试图更通用。该FOR_EACH(what, ...)
宏适用what
于变量参数列表中的所有其他参数。
因此,您只需要定义一个带有单个参数的宏,如下所示:
#define DO_STUFF(x) foo(x)
这将应用于列表中的每个参数。因此,对于您的典型示例,您需要稍微修改一下,但它仍然保持简洁:
#define PRN_STRUCT_OFFSETS_(structure, field) printf(STRINGIZE(structure)":"STRINGIZE(field)" - offset = %d\n", offsetof(structure, field));
#define PRN_STRUCT_OFFSETS(field) PRN_STRUCT_OFFSETS_(struct a, field)
你像这样应用它:
FOR_EACH(PRN_STRUCT_OFFSETS, a, b, c);
最后,一个完整的示例程序:
#include <stdio.h>
#include <stddef.h>
struct a
{
int a;
int b;
int c;
};
#define STRINGIZE(arg) STRINGIZE1(arg)
#define STRINGIZE1(arg) STRINGIZE2(arg)
#define STRINGIZE2(arg) #arg
#define CONCATENATE(arg1, arg2) CONCATENATE1(arg1, arg2)
#define CONCATENATE1(arg1, arg2) CONCATENATE2(arg1, arg2)
#define CONCATENATE2(arg1, arg2) arg1##arg2
#define FOR_EACH_1(what, x, ...) what(x)
#define FOR_EACH_2(what, x, ...)\
what(x);\
FOR_EACH_1(what, __VA_ARGS__);
#define FOR_EACH_3(what, x, ...)\
what(x);\
FOR_EACH_2(what, __VA_ARGS__);
#define FOR_EACH_4(what, x, ...)\
what(x);\
FOR_EACH_3(what, __VA_ARGS__);
#define FOR_EACH_5(what, x, ...)\
what(x);\
FOR_EACH_4(what, __VA_ARGS__);
#define FOR_EACH_6(what, x, ...)\
what(x);\
FOR_EACH_5(what, __VA_ARGS__);
#define FOR_EACH_7(what, x, ...)\
what(x);\
FOR_EACH_6(what, __VA_ARGS__);
#define FOR_EACH_8(what, x, ...)\
what(x);\
FOR_EACH_7(what, __VA_ARGS__);
#define FOR_EACH_NARG(...) FOR_EACH_NARG_(__VA_ARGS__, FOR_EACH_RSEQ_N())
#define FOR_EACH_NARG_(...) FOR_EACH_ARG_N(__VA_ARGS__)
#define FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
#define FOR_EACH_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0
#define FOR_EACH_(N, what, x, ...) CONCATENATE(FOR_EACH_, N)(what, x, __VA_ARGS__)
#define FOR_EACH(what, x, ...) FOR_EACH_(FOR_EACH_NARG(x, __VA_ARGS__), what, x, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_(structure, field) printf(STRINGIZE(structure)":"STRINGIZE(field)" - offset = %d\n", offsetof(structure, field));
#define PRN_STRUCT_OFFSETS(field) PRN_STRUCT_OFFSETS_(struct a, field)
int main(int argc, char *argv[])
{
FOR_EACH(PRN_STRUCT_OFFSETS, a, b, c);
printf("\n");
return 0;
}