Thursday, 12 September 2013

Can all for-loops be transformed to while-loops?

I previously wrote on using for as a brace-less scope using a trick by Jens Gustedt but I wanted to be able to propagate any break clause that might be used within that scope so that it would take effect in an enclosing loop or case statement.

I found a method that worked for gcc but which made use of it's compound statements.

#include 

main() {
  int a;
  for (a=1; a<=2; a++) {
    printf("Main context a=%d\n", a);

    for (int o = 0; o >=0; ({ if (o == 1) { printf("Detected break\n"); break; } }) )
      for (int i=0; !o && (o=1), i==0; o=-1, i=-1 ) { printf("Inner context\n"); break; }
  }
}

produces:
Main context a=1
Inner context
Detected break

which shows that the break statement in the inner-context was propagated to take effect in the top level loop, by means of the break statement in the compound statement of the second loop.

Thats nice, and it is the intended effect, but a for-loop of this form

for ( expression-1 ; expression-2 ; expression-3 ) statement;

is meant to be equivalent to this while loop:

expression-1 ;
while ( expression-2) {
  statement
  expression-3 ;
}

In my case, expression-3 consisted of ({ if (o == 1) { printf("Detected break\n"); break; } }) and the break clause took affect in the containing scope - no doubt because it was not part of the statement of it's associated for-loop.

But it would transform into this while-loop:

expression-1 ;
while ( expression-2) {
  statement
  printf("Detected break\n"); break ;
}

Can there be any doubt that in this while-loop, the break statement would terminate the loop itself and not any containing scope? I don't think so.

Therefore gcc compound statements in for loops open the door to high-class trickery which cannot be achieved the normal way.

1 comment:

  1. Jens Gustedt provided a sample transformation of what GCC is doing:

    http://gustedt.wordpress.com/2010/08/14/scope-bound-resource-management-with-for-scopes/#comment-872

    which gave me the hint to make this work, as I show in a later post.

    ReplyDelete