0

I have this code

#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;   
}

Can someone explain how it works this macro? especially this allocation keep = !keep what is this for

7
  • Do you have an example of its use so we can get some context? Commented Nov 30, 2015 at 20:47
  • 3
    macros are a simple text replacement. I suggest you perform this replacement (either by hand, or using a preprocessor program). If you still don't understand the code after preprocessing, most a new question. Commented Nov 30, 2015 at 20:49
  • in order to see what it does, why don't you just compile it and see what it prints?ideone.com/QKqUcm Commented Nov 30, 2015 at 20:56
  • @Anders Karlsson: I know what it does, I just want to understand the workings of code Commented Nov 30, 2015 at 21:01
  • keep is used as a logical value, !keep is the logical negation. Commented Nov 30, 2015 at 21:14

2 Answers 2

3

Expanding it out by hand:

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

becomes

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);

The outer loop iterates over the array. The inner loop creates an item to which the current array element is assigned (int *v), and then the statements in the body of the foreach loop use that item (i.e., the body of the foreach loop becomes the body of the inner for loop). The keep flag makes sure that the inner loop only executes 1 time. Trace through the logic by hand for a few iterations and you should see the pattern.

Effectively, it's treating v as an iterator over the array values. As such, it's fairly clever; you can use this macro to iterate over an array of any type, such as

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

But...

As written, this code does have some pitfalls. It won't work with dynamically-allocated arrays:

int *vals = malloc( sizeof *vals * N );
...
foreach( int *v, vals ) // bzzzzt!
  printf( "%d\n", *v );

since sizeof vals only gives you the size of the pointer variable, not the size of the allocated buffer. Similarly, it won't work on any array passed as a function parameter.

Be very suspicious of any macro that attempts to extend language syntax; it's always a hack, and almost always has a fatal weakness or two.

Sign up to request clarification or add additional context in comments.

Comments

2

The keep and keep = !keep is a trick, it can make break work in your 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.

To get more details, please refer to Does C have a "foreach" loop construct?

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.