宏的foreach循环在C中

时间:2015-11-30 20:42:57

标签: c macros

我有这段代码

#define foreach(item, array) \
    for(int keep = 1, \
            count = 0,\
            size = sizeof (array) / sizeof *(array); \
        keep && count != size; \
        keep = !keep, count++) \
      for(item = (array) + count; keep; keep = !keep)

int main(void)
{
    int values[] = { 1, 2, 3 };

    foreach(int *v, values)
        printf("value: %d\n", *v);

    return 0;   
}

有人可以解释它是如何工作的吗?特别是这个分配 keep =!keep 这是什么

2 个答案:

答案 0 :(得分:3)

手工扩展:

foreach(int *v, values)
    printf("value: %d\n", *v);

变为

for (int keep = 1, count = 0,  size = sizeof values / sizeof *(values); keep && count != size; keep = !keep, count++)
  for (int *v = (values) + count; keep; keep = !keep)
    printf("value: %d\n", *v);

外部循环遍历数组。内部循环创建一个项目,当前数组元素被赋值(int *v),然后foreach循环体中的语句使用该项(即{{1的主体)循环成为内部foreach循环的主体)。 for标志确保内循环仅执行1次。手动跟踪逻辑进行几次迭代,您应该看到模式。

有效地,它将keep视为数组v上的迭代器。因此,它相当聪明;您可以使用此宏来迭代任何类型的数组,例如

values

但是...

正如所写,这段代码确实有一些陷阱。它不能使用动态分配的数组:

double dval[N];
...
foreach( double *d, dval )
  do_something_with( *d );

因为int *vals = malloc( sizeof *vals * N ); ... foreach( int *v, vals ) // bzzzzt! printf( "%d\n", *v ); 只给出了指针变量的大小,而不是分配的缓冲区的大小。同样,它不会对作为函数参数传递的任何数组起作用。

对任何试图扩展语言语法的宏非常怀疑;它总是一个黑客,几乎总是有一两个致命的弱点。

答案 1 :(得分:2)

keepkeep = !keep是一种技巧,它可以使break中的foreach正常工作。

int *v;
foreach(v, values){
        printf("value: %d\n", *v);
        if(/*some condition*/){
            break;
        }
}
// After break, v can keep the status 
// just the same behaviour with for...break... in C language.

要了解更多详情,请参阅Does C have a "foreach" loop construct?

相关问题