我有这段代码
#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 这是什么
答案 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)
keep
和keep = !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?