是否可以在可变参数宏中迭代参数? [英] Is it possible to iterate over arguments in variadic macros?

查看:25
本文介绍了是否可以在可变参数宏中迭代参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道是否可以迭代传递给 C99 中的可变参数宏的参数或使用任何 GCC 扩展?

例如是否可以编写一个通用宏,将结构及其字段作为参数传递并打印结构中每个字段的偏移量?

像这样:

<前>结构一个{一个;国际b;国际 c;};/* PRN_STRUCT_OFFSETS 将打印每个字段的偏移量作为第一个参数传递的结构内.*/int main(int argc, char *argv[]){PRN_STRUCT_OFFSETS(struct a, a, b, c);返回0;}

解决方案

这是我今天的作业,它基于宏技巧,今天我特别了解了 __VA_NARG__ 由 Laurent Deniau 发明.无论如何,为了清楚起见,以下示例代码最多可用于 8 个字段.如果需要更多,只需通过复制扩展代码(这是因为预处理器不具有递归功能,因为它只读取文件一次).

#include #include 结构体{一个;国际b;国际 c;};结构体{一个;国际b;国际 c;国际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 将打印每个字段的偏移量作为第一个参数传递的结构内.*/#define PRN_STRUCT_OFFSETS_1(structure, field, ...) printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d
", offsetof(structure, field));#define PRN_STRUCT_OFFSETS_2(结构,字段,...)printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d
", offsetof(structure, field));PRN_STRUCT_OFFSETS_1(结构,__VA_ARGS__)#define PRN_STRUCT_OFFSETS_3(结构,字段,...)printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d
", offsetof(structure, field));PRN_STRUCT_OFFSETS_2(结构,__VA_ARGS__)#define PRN_STRUCT_OFFSETS_4(结构,字段,...)printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d
", offsetof(structure, field));PRN_STRUCT_OFFSETS_3(结构,__VA_ARGS__)#define PRN_STRUCT_OFFSETS_5(结构,字段,...)printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d
", offsetof(structure, field));PRN_STRUCT_OFFSETS_4(结构,__VA_ARGS__)#define PRN_STRUCT_OFFSETS_6(结构,字段,...)printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d
", offsetof(structure, field));PRN_STRUCT_OFFSETS_5(结构,__VA_ARGS__)#define PRN_STRUCT_OFFSETS_7(结构,字段,...)printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d
", offsetof(structure, field));PRN_STRUCT_OFFSETS_6(结构,__VA_ARGS__)#define PRN_STRUCT_OFFSETS_8(结构,字段,...)printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d
", offsetof(structure, field));PRN_STRUCT_OFFSETS_7(结构,__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("
");PRN_STRUCT_OFFSETS(struct b, a, b, c, d);返回0;}

打印出来:

struct a:a-0结构 a:b-4结构 a:c-8结构 b:a-0结构 b:b-4结构 b:c-8结构 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
", offsetof(structure, field));#define PRN_STRUCT_OFFSETS(field) PRN_STRUCT_OFFSETS_(struct a, field)

你是这样应用的:

FOR_EACH(PRN_STRUCT_OFFSETS, a, b, c);

最后是一个完整的示例程序:

#include #include 结构体{一个;国际b;国际 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, ...)什么(x);FOR_EACH_1(什么,__VA_ARGS__);#define FOR_EACH_3(what, x, ...)什么(x);FOR_EACH_2(什么,__VA_ARGS__);#define FOR_EACH_4(what, x, ...)什么(x);FOR_EACH_3(什么,__VA_ARGS__);#define FOR_EACH_5(what, x, ...)什么(x);FOR_EACH_4(什么,__VA_ARGS__);#define FOR_EACH_6(what, x, ...)什么(x);FOR_EACH_5(什么,__VA_ARGS__);#define FOR_EACH_7(what, x, ...)什么(x);FOR_EACH_6(什么,__VA_ARGS__);#define FOR_EACH_8(what, x, ...)什么(x);FOR_EACH_7(什么,__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
", 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("
");返回0;}

I was wondering if it is possible to iterate over arguments passed to a variadic macro in C99 or using any GCC extensions ?

For e.g. is it possible to write a generic macro that takes a structure and its fields passed as arguments and prints offset of each field within the structure ?

Something like this:

struct a {
    int a;
    int b;
    int c;
};

/* PRN_STRUCT_OFFSETS will print offset of each of the fields 
   within structure passed as the first argument.
*/

int main(int argc, char *argv[])
{
    PRN_STRUCT_OFFSETS(struct a, a, b, c);

    return 0;
}

解决方案

Here is my homework of the day, it's based on macro tricks and today I particularly learnt about __VA_NARG__ invented by Laurent Deniau. Anyway, the following sample code works up to 8 fields for the sake of clarity. Just extend the code by duplicating if you need more (this is because the preprocessor doesn't feature recursion, as it reads the file only once).

#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
", offsetof(structure, field));
#define PRN_STRUCT_OFFSETS_2(structure, field, ...)
  printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d
", offsetof(structure, field));
  PRN_STRUCT_OFFSETS_1(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_3(structure, field, ...)
  printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d
", offsetof(structure, field));
  PRN_STRUCT_OFFSETS_2(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_4(structure, field, ...)
  printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d
", offsetof(structure, field));
  PRN_STRUCT_OFFSETS_3(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_5(structure, field, ...)
  printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d
", offsetof(structure, field));
 PRN_STRUCT_OFFSETS_4(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_6(structure, field, ...)
  printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d
", offsetof(structure, field));
  PRN_STRUCT_OFFSETS_5(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_7(structure, field, ...)
  printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d
", offsetof(structure, field));
  PRN_STRUCT_OFFSETS_6(structure, __VA_ARGS__)
#define PRN_STRUCT_OFFSETS_8(structure, field, ...)
  printf(STRINGIZE(structure)":"STRINGIZE(field)"-%d
", 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("
");
  PRN_STRUCT_OFFSETS(struct b, a, b, c, d);

  return 0;
}

which prints out:

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


EDIT: Here is a slightly different version that tries to be more generic. The FOR_EACH(what, ...) macro applies what to every other argument in the variable argument list.

So, you just have to define a macro that takes a single argument like this:

#define DO_STUFF(x) foo(x)

which is going to be applied to every argument in the list. So, for your typical example you need to hack a bit but it still remains concise:

#define PRN_STRUCT_OFFSETS_(structure, field) printf(STRINGIZE(structure)":"STRINGIZE(field)" - offset = %d
", offsetof(structure, field));
#define PRN_STRUCT_OFFSETS(field) PRN_STRUCT_OFFSETS_(struct a, field)

And you apply it like this:

FOR_EACH(PRN_STRUCT_OFFSETS, a, b, c);

Finally, a complete sample program:

#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
", 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("
");

  return 0;
}

这篇关于是否可以在可变参数宏中迭代参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆