Arg Eval

R

rayw

Could someone give me the name of a compiler/environment where this code
[below] evaluates left to right (or, at least not right to left!) - as in
the compiler evaluates the parameter
list left to right. This is for a c programming class, and all the gcc
implentations I have to hand does this right to left. So, I'd like to give
a concrete counter example.

#include <stdio.h>

int main(void)
{
int n = 1;

/* They'd like this to result in 1, 10, 100.
*/
printf("%d %d %d", n, n *= 10, n *= 10);

return 0;
}
 
C

Christopher Benson-Manica

rayw said:
#include <stdio.h>
int main(void)
{
int n = 1;
/* They'd like this to result in 1, 10, 100.
*/

If "they" are your instructors, drop the class immediately and tell
them to learn

http://www.eskimo.com/~scs/C-faq/q3.2.html

before they presume to teach a class on C.
printf("%d %d %d", n, n *= 10, n *= 10);

This is Bad Code and you can by no means expect it to produce reliable
results even if the compiler/implementation tells you in what order it
evaluates the function arguments (and it might not, as the Standard
permits it to do).
 
M

Mike Wahler

rayw said:
Could someone give me the name of a compiler/environment where this code
[below] evaluates left to right (or, at least not right to left!) - as in
the compiler evaluates the parameter
list left to right. This is for a c programming class,

If your instructor is telling you to write code
that depends upon that, you need a new instructor.
and all the gcc
implentations I have to hand does this right to left. So, I'd like to
give
a concrete counter example.

The language standard does not specify order of
evaluation of function arguments; therefore one
should not write code that depends upon it.
#include <stdio.h>

int main(void)
{
int n = 1;

/* They'd like this to result in 1, 10, 100.
*/
printf("%d %d %d", n, n *= 10, n *= 10);

return 0;

printf("%d %d %d", n, n * 10, n * 10 * 10);

or

printf("%d %d %d", n, n * 10, n * 100);

This will always produce:
1 10 100

.... no matter the compiler.

-Mike
 
F

Flash Gordon

rayw said:
Could someone give me the name of a compiler/environment where this code
[below] evaluates left to right (or, at least not right to left!) - as in
the compiler evaluates the parameter
list left to right.

Not here, or at least not reliably, since the order of evaluation of
parameters in unspecified according to the standard, so the compiler
could produce code that evaluates them in a different order on each run.
> This is for a c programming class, and all the gcc
implentations I have to hand does this right to left. So, I'd like to give
a concrete counter example.

If you were asked to do this in class then it was a singularly pointless
assignment.
#include <stdio.h>

int main(void)
{
int n = 1;

/* They'd like this to result in 1, 10, 100.
*/
printf("%d %d %d", n, n *= 10, n *= 10);

This invokes undefined behaviour, which means that literally anything
can happen.
1) n is modified twice without an intervening sequence point which is
undefined behaviour
2) n is used for a purpose other than calculating the new value of n
which I believe also invokes undefined behaviour.

I can certainly real ways it could produce 10 10 10 as output.

This is all strongly related to stuff in the comp.lang.c FAQ, most
explicitly http://www.eskimo.com/~scs/C-faq/q3.2.html
 
B

Barry Schwarz

Could someone give me the name of a compiler/environment where this code
[below] evaluates left to right (or, at least not right to left!) - as in
the compiler evaluates the parameter
list left to right. This is for a c programming class, and all the gcc
implentations I have to hand does this right to left. So, I'd like to give
a concrete counter example.

#include <stdio.h>

int main(void)
{
int n = 1;

/* They'd like this to result in 1, 10, 100.
*/
printf("%d %d %d", n, n *= 10, n *= 10);

Since this code invokes undefined behavior, you are on a wild goose
chase from the beginning.
return 0;
}


<<Remove the del for email>>
 
R

Razzer

Flash said:
This invokes undefined behaviour, which means that literally anything
can happen.
1) n is modified twice without an intervening sequence point which is
undefined behaviour

Isn't the comma operator a sequence point? Moreover, isn't the passing
each argument a sequence point in of itself?
2) n is used for a purpose other than calculating the new value of n
which I believe also invokes undefined behaviour.

Only if it is in the same expression.
 
A

Artie Gold

Razzer said:
Isn't the comma operator a sequence point? Moreover, isn't the passing
each argument a sequence point in of itself?
The comma operator is indeed a sequence point. The comma(s) in an
argument list, however, are *not* comma operators. Different animal.[snip]

HTH,
--ag
 
M

Martin Ambuhl

Isn't the comma operator a sequence point? Moreover, isn't the passing
each argument a sequence point in of itself?

There is no comma operator anywhere in that statement, so whether a
comma operator marks a sequence point is irrelevant.
 
C

Chris Torek

Could someone give me the name of a compiler/environment where this code
[below] evaluates left to right (or, at least not right to left!) ...
all the gcc implentations I have to hand does this right to left.
So, I'd like to give a concrete counter example.

#include <stdio.h>

int main(void)
{
int n = 1;

/* They'd like this to result in 1, 10, 100.
*/
printf("%d %d %d", n, n *= 10, n *= 10);

return 0;
}

Indeed, as everyone else has noted, this results in undefined
behavior. The question, however, is whether someone has an example
system on which (a) output is produced, and (b) the output is
"1 10 100". (It would help to add a newline.)

The old Pyramid C compiler would have done that, as it evaluated
the first 12 arguments left-to-right. Arguments beyond the first
twelve were evaluated right-to-left (and before the first twelve
were handled left-to-right). This was because most parameters are
passed in the Parameter Registers, pr0 through pr11 inclusive,
while those that do not fit are passed on a conventional stack.
(In the callee, the registers are named pr0 through pr11 -- the
caller addresses them as tr0 through tr11, the temporary or transfer
registers. Normally these are available for scratch computations.
Return values go in pr0 so that the caller sees them in tr0.)

It is generally difficult to find compilers that work strictly
L-to-R: good compilers often seem to do the evaluation in "apparently
random order", while poor compilers usually do them in whatever
order is easiest on the target hardware, and common target hardware
happens to cause the latter to be R-to-L.

Presumably the reason for the desire for "1 10 100" output is to
demonstrate that not all compilers produce "100 10 1", in an effort
to convince programmers that they should avoid such code. But
those who will not be convinced by the text of the C Standards
might also not be convinced by counterexamples: "Why, those compilers
are just broken," they might say.

Still, one handy counterexample I have is a Mac G4 (PowerPC) running
OS X 10.2 (one of these days I should upgrade it). After fixing
the code above to include a terminating newline, and compiling with
"cc" (which is Apple GCC version 1175 "based on gcc version 3.1
20020420 (prerelease)"), I get:

% cc -o t t.c
% ./t
100 10 100

The output remains unchanged when optimized (with -O or -O2).

The PowerPC, MIPS, and SPARC are three good architectures to
try, as all three generally use registers for parameter-passing.

Note that calling a function other than printf() might change the
result on some machines, because printf() is a variable-argument
function, and there are good reasons to want to use different
calling conventions for fixed vs variable argument functions.
 
F

Flash Gordon

Razzer said:
Isn't the comma operator a sequence point? Moreover, isn't the passing
each argument a sequence point in of itself?

Other have noted there is no comma operator and there no sequence point
between evaluation of parameters.
Only if it is in the same expression.

No, between sequence points. In section 6.5 of N1224 it says
| 2 Between the previous and next sequence point an object shall have
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| its stored value modified at most once by the evaluation of an
| expression. Furthermore, the prior value shall be read only to
| determine the value to be stored.71)

No where does it say this only applies to individual expressions. If it
did then it would make this explicit. So
printf("%d %d", n, n *= 10);
would also be undefined behaviour in my opinion since you are reading n
for a purpose other than calculating its new value between sequence points.
 
R

rayw

Chris Torek said:
Could someone give me the name of a compiler/environment where this code
[below] evaluates left to right (or, at least not right to left!) ...
all the gcc implentations I have to hand does this right to left.
So, I'd like to give a concrete counter example.

#include <stdio.h>

int main(void)
{
int n = 1;

/* They'd like this to result in 1, 10, 100.
*/
printf("%d %d %d", n, n *= 10, n *= 10);

return 0;
}

Indeed, as everyone else has noted, this results in undefined
behavior. The question, however, is whether someone has an example
system on which (a) output is produced, and (b) the output is
"1 10 100". (It would help to add a newline.)

The old Pyramid C compiler would have done that, as it evaluated
the first 12 arguments left-to-right. Arguments beyond the first
twelve were evaluated right-to-left (and before the first twelve
were handled left-to-right). This was because most parameters are
passed in the Parameter Registers, pr0 through pr11 inclusive,
while those that do not fit are passed on a conventional stack.
(In the callee, the registers are named pr0 through pr11 -- the
caller addresses them as tr0 through tr11, the temporary or transfer
registers. Normally these are available for scratch computations.
Return values go in pr0 so that the caller sees them in tr0.)

It is generally difficult to find compilers that work strictly
L-to-R: good compilers often seem to do the evaluation in "apparently
random order", while poor compilers usually do them in whatever
order is easiest on the target hardware, and common target hardware
happens to cause the latter to be R-to-L.

Presumably the reason for the desire for "1 10 100" output is to
demonstrate that not all compilers produce "100 10 1", in an effort
to convince programmers that they should avoid such code. But
those who will not be convinced by the text of the C Standards
might also not be convinced by counterexamples: "Why, those compilers
are just broken," they might say.

Still, one handy counterexample I have is a Mac G4 (PowerPC) running
OS X 10.2 (one of these days I should upgrade it). After fixing
the code above to include a terminating newline, and compiling with
"cc" (which is Apple GCC version 1175 "based on gcc version 3.1
20020420 (prerelease)"), I get:

% cc -o t t.c
% ./t
100 10 100

The output remains unchanged when optimized (with -O or -O2).

The PowerPC, MIPS, and SPARC are three good architectures to
try, as all three generally use registers for parameter-passing.

Note that calling a function other than printf() might change the
result on some machines, because printf() is a variable-argument
function, and there are good reasons to want to use different
calling conventions for fixed vs variable argument functions.

That's just the job - ta.

I should have made it clear that I'm teaching this course, and that the code
was entered by a student. Obviously, I explained the mistake, and then
actually walked through what was happening here with the class.

All I was after -just for interest'ss sake- was the name of a compiler that
happened to eval left to right.

rayw
 
J

Jalapeno

rayw said:
Could someone give me the name of a compiler/environment where this code
[below] evaluates left to right (or, at least not right to left!) - as in
the compiler evaluates the parameter
list left to right. This is for a c programming class, and all the gcc
implentations I have to hand does this right to left. So, I'd like to give
a concrete counter example.

#include <stdio.h>

int main(void)
{
int n = 1;

/* They'd like this to result in 1, 10, 100.
*/
printf("%d %d %d", n, n *= 10, n *= 10);

return 0;
}

The z/OS C version 1 release 6 compiler from IBM for their Mainframes:
(This was compiled and run in batch under JES2)

5694A01 V1 R6 z/OS C 'SYS05297.T091012.RA000.T9232EHD.SOURCE.H02'


* * * * * S O U R C E * * * * *


LINE STMT


*...+....1....+....2....+....3....+....4....+....5....+....6....+.
1 |#include <stdio.h>

2 |

3 |int main(void)

4 |{

5 1 | int n = 1;

6 |

7 | /* They'd like this to result in 1, 10, 100.

8 | */

9 2 | printf("%d %d %d", n, n *= 10, n *= 10);

10 |

11 3 | return 0;

12 |}

* * * * * E N D O F S O U R C E * *


Display Filter View Print Options Help
------------------------------------------------------------------
SDSF OUTPUT DISPLAY T9232EHB JOB17312 DSID 102 LINE 0 COL
COMMAND INPUT ===> SCRO
********************************* TOP OF DATA *********************
1 10 100
******************************** BOTTOM OF DATA *******************
 
R

rayw

Jalapeno said:
Could someone give me the name of a compiler/environment where this code
[below] evaluates left to right (or, at least not right to left!) - as in
the compiler evaluates the parameter
list left to right. This is for a c programming class, and all the gcc
implentations I have to hand does this right to left. So, I'd like to
give
a concrete counter example.

#include <stdio.h>

int main(void)
{
int n = 1;

/* They'd like this to result in 1, 10, 100.
*/
printf("%d %d %d", n, n *= 10, n *= 10);

return 0;
}

The z/OS C version 1 release 6 compiler from IBM for their Mainframes:
(This was compiled and run in batch under JES2)

5694A01 V1 R6 z/OS C 'SYS05297.T091012.RA000.T9232EHD.SOURCE.H02'


* * * * * S O U R C E * * * * *


LINE STMT


*...+....1....+....2....+....3....+....4....+....5....+....6....+.
1 |#include <stdio.h>

2 |

3 |int main(void)

4 |{

5 1 | int n = 1;

6 |

7 | /* They'd like this to result in 1, 10, 100.

8 | */

9 2 | printf("%d %d %d", n, n *= 10, n *= 10);

10 |

11 3 | return 0;

12 |}

* * * * * E N D O F S O U R C E * *


Display Filter View Print Options Help
------------------------------------------------------------------
SDSF OUTPUT DISPLAY T9232EHB JOB17312 DSID 102 LINE 0 COL
COMMAND INPUT ===> SCRO
********************************* TOP OF DATA *********************
1 10 100
******************************** BOTTOM OF DATA *******************

Excellent - thanks!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top