10

Consider the following code in C:

void main()
{
    int a=0;

    for(printf("\nA"); a; printf("\nB"));

    printf("\nC");
    printf("\nD");     
}

When I compile it using Turb C++ version 3.0 and gcc-4.3.4, I get the following as the output in BOTH the cases :

A
C
D

However, if I compile the following code:

void main()
{
    for(printf("\nA"); 0; printf("\nB"));

    printf("\nC");
    printf("\nD");
}

The output by gcc-4.3.4 is the same as in the previous case but turbo c++ 3.0 produces the following output :

A
B
C
D

First of all, I have no idea what's happening here! Plus, how come the output by the gcc compiler is the same for both the codes but in the case of turboc++ 3.0 compiler, the output is different? Can someone please shed some light?

EDIT :

Actually someone was asked this question in an interview for an IT company and when he failed to give the answer, the interviewer gave this explanation. But I find this to be stupid. How can you ask someone to use a "bug" as if it's a "facility" provided by the language? For it to be called a "facility" and "technique", whether we pass 0 as a literal in the second expression or a variable whose value is 0, the outcome should have been the same.

Am I wrong concluding that the interviewer was very dumb to ask a question like that and that it shows his incompetence?

finitenessofinfinity
  • 989
  • 5
  • 13
  • 24
  • 5
    This is an interesting difference in compilers, but why in the world would you use that sort of `for` loop in the first place? – JAB Jun 18 '12 at 16:10
  • It looks to me that you have completely misunderstood the syntax for the "for" loop in C? You can't just guess how to write things in a programming language, you need a book or web course or something! – Thomas Padron-McCarthy Jun 18 '12 at 16:11
  • 3
    @ThomasPadron-McCarthy Actually, the syntax is just fine. It doesn't seem to have any good use, but it's perfectly valid, just as the sentence "My cold is a toe" is perfectly valid syntactically, but is a nonsense phrase. The first portion, `printf("\nA")`, will be executed at the start of the looping; the sentinel expression, which causes the loop to stop executing when it evaluates to false/0, is a `a` for the first one (which == 0) and a literal `0` for the second; [cont.] – JAB Jun 18 '12 at 16:13
  • 2
    @Naveen: Clearly its to find weird bugs in it. – hugomg Jun 18 '12 at 16:14
  • 1
    [cont.] the final portion, `printf("\nB")`, which is normally executed at the end of every iteration of the loop, shouldn't be executed at all as the sentinel evaluates to 0 to start with, and in 3/4 cases that is the case. – JAB Jun 18 '12 at 16:17
  • 3
    It's a compiler bug. One can find many more questions like this one on the Internet concerning this strange behaviour of `Turbo C++ 3.0` from 10 and more years ago. Even `for (;0;) statement;` makes `statement` to execute. Please note that TC++ 3.0 comes from an era when most DOS compilers were not standards compliant and even implemented incomptabile extensions just to lock their users in (e.g. TC++ vs MSC). – Hristo Iliev Jun 18 '12 at 16:46

5 Answers5

12

The TCC output for the 2nd example is wrong.

From the C99 standard:

The statement

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

behaves as follows: The expression expression-2 is the controlling expression that is evaluated before each execution of the loop body. The expression expression-3 is evaluated as a void expression after each execution of the loop body. [...]

Obviously, there are no iterations here, so expression-3 should never be executed.

Similarly, in the C90 standard (or at least in a draft that I found), it says:

Except for the behavior of a continue statement in the loop body, the statement

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

and the sequence of statements

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

are equivalent.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • Obviously Turbo C++ 3.0 predates C99 by 8 years. It could be some weird optimisation technique. – Hristo Iliev Jun 18 '12 at 16:26
  • I agree. It could also be a compiler bug and probably it is. It is not normal for a compiler for the resource constrained x86 architecture to generate unnecessary function calls. – Hristo Iliev Jun 18 '12 at 16:30
3

Turbo C++ 3.0 was release in the 1990's, and was very quickly followed up with a release of 3.1.

I would guess that your ancient compiler had a number of bugs in it, which were updated quickly. In addition it might not have had such bugs, but may have emitted optimized assembly which fails under the new pipe lining architectures.

In any event, it is guaranteed that Turbo C++ 3.0 is not supported on your current platform. When it comes to a compiler not being supported because the platform was created nearly 20 years later, you cannot really fault it for emitting the wrong program.

Edwin Buck
  • 69,361
  • 7
  • 100
  • 138
2

The gcc output is correct.

The Turbo C++ 3.0 output in the first case is correct.

The TurboC++ 3.0 output in the second case is wrong.

You appear to have found an edge case, leading to incorrect code generation, in the Turbo C++ 3.0 compiler.

A for-stmt in C or C++ has the general syntax

for ( initialization ; test ; reinitialization ) stmt

The initializations are performed once, before the loop starts. The test is performed at the TOP of the loop. If the test is true, the stmt is performed, and then the reinitializations, and the loop repeats.

In your case, printf("\nA") is the initialization, a (or 0) is the test, printf("\nB") is the reinitialization, and the stmt is empty.

You should have seen the A (and you did). The test should have failed on the first pass, meaning you should never have seen the stmt (but you don't know), and you should never have seen the B. This is where Turbo C++ 3.0 screwed up on the second test.

John R. Strohm
  • 7,547
  • 2
  • 28
  • 33
1

What is the full "for" loop syntax in C (and others in case they are compatible)?

This question quotes the applicable part of the standard. The 3rd expression shouldn't be evaluated unless the loop executes at least once. So, I'd say that in the 2nd case the old compiler is wrong to print 'B'.

Community
  • 1
  • 1
Joe
  • 41,484
  • 20
  • 104
  • 125
1

the semantics of for is that the first expression is evaluated (initializer) then the second expression is evaluated (terminator) then if the terminator evaluated to non-zero the body of the for is executed, then the third expression (advancement) is evaluated and back to evaluating the terminator.

Since you have no body, that part amounts to no expressions evaluated. Based on this the loop should be executed as follows:

printf("\nA");
a; // yields 0 -> terminate loop

This is indeed what happens.

In your second example the same should happen (as is for gcc) as 0 evaluates to 0.

It is possible that turbo C++ -- seeing the 0 constant -- attempted to perform some sort of a loop unrolling optimization (and failed to do it properly)

Attila
  • 28,265
  • 3
  • 46
  • 55
  • I almost thought the loop unrolling story plausible, until I realized it was not `i < 0`, but instead just `0`, what is not a probable target for loop unrolling optimization. – lvella Jun 18 '12 at 16:43