1

Given

int x[10];
int y[10];
int n = 10;

Version 1

int i = 0;
while (i < n)
  y[i] = x[i++];

Version 2

for (int i = 0; i < n; i++)
  y[i] = x[i]

Are the two versions always equivalent? If not, when are they not equivalent?

Juto
  • 1,246
  • 1
  • 13
  • 24

3 Answers3

7

This line:

y[i] = x[i++];

is undefined behaviour. You cannot use i and i++ within the same statement.

Your Version 2, with the i++ inside the for control statement, is fine.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • Why is the first version undefined behaviour, and if the machine reads from left to right, when doesn't it make sense? Please look at @moshe-beeri's answer? – Juto Sep 02 '13 at 21:43
  • 2
    @Juto: Perhaps your compiler, with the current options settings you are using, compiles that statement as if it were reading from left to right. However, that is by no means guaranteed by the language standard, and a different compiler or even different settings on your compiler, could generate different code that does not produce the same result. – Greg Hewgill Sep 02 '13 at 21:47
  • @Juto Read: [Undefined Behavior and Sequence Points](http://stackoverflow.com/questions/4176328/undefined-behavior-and-sequence-points) – Grijesh Chauhan Sep 03 '13 at 05:13
  • @Juto *Why is the first version undefined behaviour?* Because the standard says so and it has a pretty good reason for it : just take an example -- `y =4; y = n++ + n++;` if one were to follow the precedence operations the value of y would probably be `9` but it could be even `8` for that matter . That's why C defined sequence points and guarantees that all the `side effects` will take place before proceeding to next statement i.e after the sequence points. If you want to change the value twice between the two sequence points it is not guaranteed which will evaluate first and so it is illegal. – 0decimal0 Sep 03 '13 at 08:29
  • 1
    @GregHewgill Although it was a good answer and there are at least 1000 posts regarding this I would still advise a little explanation , just a little to *why its undefined behavior* . Even one or two links to those answers would be a nice idea ... +1 nevertheless :) – 0decimal0 Sep 03 '13 at 08:33
4

If we code around the undefined behaviour correctly diagnosed by Greg Hewgill in his answer, then we might end up with code like this:

int x[10] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
int y[10];
int n = 10;

i = 0;
while (i < n)
{
    if (i % 3 == 0)
        continue;
    y[i] = x[i];
    i++;
//cont: ;
}

for (i = 0; i < n; i++)
{
    if (i % 3 == 0)
        continue;
    y[i] = x[i];
}

These loops are not equivalent because of the continue statements — and, indeed, the first is an infinite loop. And the loop bodies could be written without the continue, but I wanted something simple to illustrate the behaviour of continue in a while loop and a for loop.

The for loop behaves sanely, not initializing elements y[0], y[3], y[6] or y[9], but otherwise working perfectly well.

The while loop looks similar, but the continue; statement is equivalent to goto cont; where cont is the label that is commented out, immediately before the closing brace. Note that it skips the increment of i, which is why the loop is 'infinite'.

So, the two loops are equivalent if there is no continue inside.

Note that the related loop:

for (int i = 0; i < n; i++)
{
    if (i % 3 == 0)
        continue;
    y[i] = x[i];
}

is not quite identical to the first for loop. The variable i is available outside (after) the loop in the while loop and the first for loop; it is not available when the variable is declared in the for loop itself.

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • I am not sure why you added the `continue` block between the lines, in the question, the `continue` did not present? – Juto Sep 02 '13 at 22:37
  • Correct that the `continue` was not present in the question. I added it to explain the one situation where `for` loops and `while` loops are different — when the code does not invoke undefined behaviour. In other circumstances, if you avoid undefined behaviour, the two loops are 'the same', as I also stated. So, unless you have a `continue` statement, the `while` loop and the `for` loop are equivalent. If you have a `continue` statement, they are not equivalent. And I also noted a minor difference between `for (i = 0; ...)` and `for (int i = 0; ...)` which was not in the question. – Jonathan Leffler Sep 02 '13 at 22:43
  • I did assume that your invocation of undefined behaviour was unintentional and fixable (`i = 0; while (i < n) { y[i] = x[i]; i++; }`). If your intention was to investigate the benefits or otherwise of undefined behaviour, then that is somewhat different from what your question appears to be. – Jonathan Leffler Sep 02 '13 at 22:45
0

Good question, take a look here you can find a nice c to assembler web compiler I compared the two versions and there are minor assembly differences in the loop implementation. the functionality seems exactly the same therefor I conclude both samples are always equivalent. While case: this is the while loop For case: this is the for loop

moshe beeri
  • 2,007
  • 1
  • 17
  • 25
  • You have found a compiler, using particular settings, that happens to generate code for the two examples that is equivalent. However, because the first example invokes undefined behaviour, this is only one possible outcome. – Greg Hewgill Sep 03 '13 at 05:24
  • Yes it always will be compiler dependent. but it site uses GNU gcc which considered to be one of the best compilers. – moshe beeri Sep 03 '13 at 19:07