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

Kevin
  • 1,151
  • 1
  • 10
  • 18
  • Do you have an example of its use so we can get some context? – Peter M Nov 30 '15 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. – M.M Nov 30 '15 at 20:49
  • in order to see what it does, why don't you just compile it and see what it prints?https://ideone.com/QKqUcm – AndersK Nov 30 '15 at 20:56
  • @Anders Karlsson: I know what it does, I just want to understand the workings of code – Kevin Nov 30 '15 at 21:01
  • `keep` is used as a logical value, `!keep` is the logical negation. – Jens Gustedt Nov 30 '15 at 21:14
  • @Kevin Take a piece of paper and pencil and walk trough the code while writing down variables' values for each iteration. – this Nov 30 '15 at 21:24
  • Or you could step through the code in debugger. Pen and paper would of course work too. While you do this, think of all the people who will see this code after you, scratch their heads, and try to figure out what is going on here. – void_ptr Nov 30 '15 at 21:27

2 Answers2

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.

John Bode
  • 119,563
  • 19
  • 122
  • 198
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?

Community
  • 1
  • 1
Eric Tsui
  • 1,924
  • 12
  • 21