是否有可能遍历在复杂的宏参数呢? [英] Is it possible to iterate over arguments in variadic macros?

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

问题描述

我不知道是否有可能遍历传递给C99一个可变参数宏或使用任何GCC扩展参数?

有关如是否有可能写一个通用的宏,采用的结构中每个字段的偏移量参数并打印通过结构及其字段?

事情是这样的:


结构A {
    int类型的;
    INT B:
    INT℃;
};/ * PRN_STRUCT_OFFSETS将打印的每个字段的偏移
   结构中传递的第一个参数。
* /INT主(INT ARGC,CHAR *的argv [])
{
    PRN_STRUCT_OFFSETS(结构A,A,B,C);    返回0;
}


解决方案

下面是我一天的功课,它是基于宏观的技​​巧,今天我特别了解<一个href=\"http://groups.google.com/group/comp.std.c/browse_thread/thread/77ee8c8f92e4a3fb/346fc464319b1ee5\"><$c$c>__VA_NARG__洛朗DENIAU发明的。不管怎样,下面的示例code工作到为清楚起见8个字段。只是通过复制扩展code,如果你需要更多的(这是因为preprocessor不具有递归,因为它读取文件仅一次)。

 的#include&LT;&stdio.h中GT;
#包括LT&;&STDDEF.H GT;一个结构
{
  int类型的;
  INT B:
  INT℃;
};结构b
{
  int类型的;
  INT B:
  INT℃;
  INT D组;
};#定义STRINGIZE(ARG)STRINGIZE1(ARG)
#定义STRINGIZE1(ARG)STRINGIZE2(ARG)
#定义STRINGIZE2(ARG)#arg#定义CONCATENATE(ARG1,ARG2)CONCATENATE1(ARG1,ARG2)
#定义CONCATENATE1(ARG1,ARG2)CONCATENATE2(ARG1,ARG2)
#定义CONCATENATE2(ARG1,ARG2)ARG1 ARG2 ##/ * PRN_STRUCT_OFFSETS将打印的每个字段的偏移
 结构中传递的第一个参数。
 * /
#定义PRN_STRUCT_OFFSETS_1(结构,场,...)的printf(STRINGIZE(结构)​​:STRINGIZE(场)内容 - %d \\ n,offsetof(结构域));
#定义PRN_STRUCT_OFFSETS_2(结构,场,...)\\
  的printf(STRINGIZE(结构)​​:STRINGIZE(场)内容 - %d \\ n,offsetof(结构域)); \\
  PRN_STRUCT_OFFSETS_1(结构,__VA_ARGS__)
#定义PRN_STRUCT_OFFSETS_3(结构,场,...)\\
  的printf(STRINGIZE(结构)​​:STRINGIZE(场)内容 - %d \\ n,offsetof(结构域)); \\
  PRN_STRUCT_OFFSETS_2(结构,__VA_ARGS__)
#定义PRN_STRUCT_OFFSETS_4(结构,场,...)\\
  的printf(STRINGIZE(结构)​​:STRINGIZE(场)内容 - %d \\ n,offsetof(结构域)); \\
  PRN_STRUCT_OFFSETS_3(结构,__VA_ARGS__)
#定义PRN_STRUCT_OFFSETS_5(结构,场,...)\\
  的printf(STRINGIZE(结构)​​:STRINGIZE(场)内容 - %d \\ n,offsetof(结构域)); \\
 PRN_STRUCT_OFFSETS_4(结构,__VA_ARGS__)
#定义PRN_STRUCT_OFFSETS_6(结构,场,...)\\
  的printf(STRINGIZE(结构)​​:STRINGIZE(场)内容 - %d \\ n,offsetof(结构域)); \\
  PRN_STRUCT_OFFSETS_5(结构,__VA_ARGS__)
#定义PRN_STRUCT_OFFSETS_7(结构,场,...)\\
  的printf(STRINGIZE(结构)​​:STRINGIZE(场)内容 - %d \\ n,offsetof(结构域)); \\
  PRN_STRUCT_OFFSETS_6(结构,__VA_ARGS__)
#定义PRN_STRUCT_OFFSETS_8(结构,场,...)\\
  的printf(STRINGIZE(结构)​​:STRINGIZE(场)内容 - %d \\ n,offsetof(结构域)); \\
  PRN_STRUCT_OFFSETS_7(结构,__VA_ARGS__)#定义PRN_STRUCT_OFFSETS_NARG(...)PRN_STRUCT_OFFSETS_NARG _(__ VA_ARGS__,PRN_STRUCT_OFFSETS_RSEQ_N())
#定义PRN_STRUCT_OFFSETS_NARG _(...)PRN_STRUCT_OFFSETS_ARG_N(__ VA_ARGS__)
#定义PRN_STRUCT_OFFSETS_ARG_N(_1,_2,_3,_4,_5,_6,_7,_8,N,...)N
#定义PRN_STRUCT_OFFSETS_RSEQ_N()8,7,6,5,4,3,2,1,0#定义PRN_STRUCT_OFFSETS_(N,结构,场,...)CONCATENATE(PRN_STRUCT_OFFSETS_,N)(结构,领域,__VA_ARGS__)的#define PRN_STRUCT_OFFSETS(结构,字段,...)PRN_STRUCT_OFFSETS_(PRN_STRUCT_OFFSETS_NARG(场,__VA_ARGS__),结构,字段,__VA_ARGS__)INT主(INT ARGC,CHAR *的argv [])
{
  PRN_STRUCT_OFFSETS(结构A,A,B,C);
  的printf(\\ n);
  PRN_STRUCT_OFFSETS(结构B,A,B,C,D);  返回0;
}

打印出:

 结构答:0
结构A:B-4
结构A:C-8结构A:A-0
结构B:B-4
结构B:C-8
结构A:D-12


编辑:下面是试图成为更通用的一个稍微不同的版本的for_each(什么,...)宏适用什么来变量参数列表中的每个其他参数。

所以,你只需要定义一个宏接受一个参数是这样的:

 的#define DO_STUFF(X)富(X)

这是将要施加到列表中的每个参数。
因此,对于您典型的例子,你需要破解了一点,但它仍然是简洁的:

 的#define PRN_STRUCT_OFFSETS_(结构,场)的printf(STRINGIZE(结构)​​:STRINGIZE(场) - 偏移=%d个\\ N,offsetof(结构域)) ;
#定义PRN_STRUCT_OFFSETS(场)PRN_STRUCT_OFFSETS_(结构一,场)

和应用它是这样的:

 的for_each(PRN_STRUCT_OFFSETS,A,B,C);

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

 的#include&LT;&stdio.h中GT;
#包括LT&;&STDDEF.H GT;一个结构
{
  int类型的;
  INT B:
  INT℃;
};#定义STRINGIZE(ARG)STRINGIZE1(ARG)
#定义STRINGIZE1(ARG)STRINGIZE2(ARG)
#定义STRINGIZE2(ARG)#arg#定义CONCATENATE(ARG1,ARG2)CONCATENATE1(ARG1,ARG2)
#定义CONCATENATE1(ARG1,ARG2)CONCATENATE2(ARG1,ARG2)
#定义CONCATENATE2(ARG1,ARG2)ARG1 ARG2 ###定义FOR_EACH_1(什么,X,...)什么(X)
#定义FOR_EACH_2(什么,X,...)\\
  什么(X); \\
  FOR_EACH_1(什么,__VA_ARGS__);
#定义FOR_EACH_3(什么,X,...)\\
  什么(X); \\
  FOR_EACH_2(什么,__VA_ARGS__);
#定义FOR_EACH_4(什么,X,...)\\
  什么(X); \\
  FOR_EACH_3(什么,__VA_ARGS__);
#定义FOR_EACH_5(什么,X,...)\\
  什么(X); \\
 FOR_EACH_4(什么,__VA_ARGS__);
#定义FOR_EACH_6(什么,X,...)\\
  什么(X); \\
  FOR_EACH_5(什么,__VA_ARGS__);
#定义FOR_EACH_7(什么,X,...)\\
  什么(X); \\
  FOR_EACH_6(什么,__VA_ARGS__);
#定义FOR_EACH_8(什么,X,...)\\
  什么(X); \\
  FOR_EACH_7(什么,__VA_ARGS__);#定义FOR_EACH_NARG(...)FOR_EACH_NARG _(__ VA_ARGS__,FOR_EACH_RSEQ_N())
#定义FOR_EACH_NARG _(...)FOR_EACH_ARG_N(__ VA_ARGS__)
#定义FOR_EACH_ARG_N(_1,_2,_3,_4,_5,_6,_7,_8,N,...)N
#定义FOR_EACH_RSEQ_N()8,7,6,5,4,3,2,1,0#定义FOR_EACH_(N,什么,X,...)CONCATENATE(FOR_EACH_,N)(什么,X,__VA_ARGS__)
#定义的for_each(什么,X,...)FOR_EACH_(FOR_EACH_NARG(X,__VA_ARGS__),什么,X,__VA_ARGS__)#定义PRN_STRUCT_OFFSETS_(结构,场)的printf(STRINGIZE(结构)​​:STRINGIZE(场) - 偏移=%d个\\ N,offsetof(结构域));
#定义PRN_STRUCT_OFFSETS(场)PRN_STRUCT_OFFSETS_(结构一,场)INT主(INT ARGC,CHAR *的argv [])
{
  的for_each(PRN_STRUCT_OFFSETS,A,B,C);
  的printf(\\ n);  返回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\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;
}

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\n", 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\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;
}

这篇关于是否有可能遍历在复杂的宏参数呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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