[comp.std.c] nonportable code or incorrect compilers?

jkrueger@daitc.ARPA (Jonathan Krueger) (06/25/88)

Here's a question of portability and language standards that came up in
a real life program.  According to K&R or ANSI, predict the output of
the following code:

#define	DEFCONST	1.05
main()
{
	int	count = 800;

	printf("count is %d, ", count);
	count *= DEFCONST;
	printf("now %d\n", count);
}

My prediction, based on K&R, was the output:
	count is 800, now 839
Indeed, the Pyramid 98x produces exactly this output.
But your mileage may vary.  4.2BSD VAX, Gould, and Sun-3 produce output:
	count is 800, now 800
Which brings me to the question: is this code non-portable, or do
three out of four compilers surveyed fail to correctly implement K&R?

The relevant K&R references appear to be 2.10, Assignment Operators
and Expresssions:
	"If e1 and e2 are expressions, then
		e1 op= e2
	 is equivalent to
		e1 = (e1) op (e2)
	 except that e1 is computed only once."
and 2.7, Type Conversions:
	"float is converted to double, then if either operand is
	 double, the other is converted to double, and the result
	 is double"

Putting it all together, does "e1 is computed only once" imply lack of
ordinary automatic type conversion for e1 and expressions of which it
is a part?  Or does "computed" mean "value derived for", and K&R
in no way implies different type handling from the unabbreviated
expression?  And does ANSI clear up this ambiguity?

-- Jon Krueger

ken (Ken Yap) (06/25/88)

I can't repeat your problem. What OS version have you? What compilers?

Script started on Fri Jun 24 19:49:06 1988
cursa.cs.rochester.edu% cat y.c
#define	DEFCONST	1.05
main()
{
	int	count = 800;

	printf("count is %d, ", count);
	count *= DEFCONST;
	printf("now %d\n", count);
}
cursa.cs.rochester.edu% cc -o y y.c
cursa.cs.rochester.edu% ./y
count is 800, now 840
cursa.cs.rochester.edu%
script done on Fri Jun 24 19:49:30 1988

Cursa is a Sun 3/50 running SunOS 3.4. On a Vax 11/750 running BSD 4.3
it gives

count is 800, now 839

	Ken

gwyn@brl-smoke.ARPA (Doug Gwyn ) (06/25/88)

In article <133@daitc.ARPA> jkrueger@daitc.ARPA (Jonathan Krueger) writes:
>My prediction, based on K&R, was the output:
>	count is 800, now 839
>Indeed, the Pyramid 98x produces exactly this output.
>But your mileage may vary.  4.2BSD VAX, Gould, and Sun-3 produce output:
>	count is 800, now 800

There is no ambiguity; the Pyramid has produced the correct answer
and the other three compilers are wrong.  The SVR2 VAX PCC also gets
this right, so presumably all recent 3B CCSes do also.

The code is "portable" to correct compilers.  Obviously it is not
"portable" to ALL compilers, as you have shown.  Nag your system
vendors to fix their compilers.

chris@mimsy.UUCP (Chris Torek) (06/27/88)

In article <133@daitc.ARPA> jkrueger@daitc.ARPA (Jonathan Krueger) writes:
[only the following three lines are needed]
>#define	DEFCONST	1.05
>	int	count = 800;
>	count *= DEFCONST;

The correct result is 840 (or something nearby, such as 839, depending
on roundoff error).

>Indeed, the Pyramid 98x produces exactly this output.
>But your mileage may vary.  4.2BSD VAX, Gould, and Sun-3 produce output:
>	count is 800, now 800
>Which brings me to the question: is this code non-portable, or do
>three out of four compilers surveyed fail to correctly implement K&R?

Three out of four compilers surveyed failed to correctly implement K&R.

The bug is an easy one to commit in PCC.  It was fixed some time ago
(I think it was fixed in 4.3BSD).  Try also

	f() {
		unsigned *a();
		int b();

		*a() %= b();
	}

and see whether the code generated is correct.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

16012_3045@uwovax.uwo.ca (Paul Gomme) (06/28/88)

In article <133@daitc.ARPA>, jkrueger@daitc.ARPA (Jonathan Krueger) writes:
> Here's a question of portability and language standards that came up in
> a real life program.  According to K&R or ANSI, predict the output of
> the following code:
> 
> #define	DEFCONST	1.05
> main()
> {
> 	int	count = 800;
> 
> 	printf("count is %d, ", count);
> 	count *= DEFCONST;
> 	printf("now %d\n", count);
> }
> 
> My prediction, based on K&R, was the output:
> 	count is 800, now 839
> Indeed, the Pyramid 98x produces exactly this output.
> But your mileage may vary.  4.2BSD VAX, Gould, and Sun-3 produce output:
> 	count is 800, now 800
> Which brings me to the question: is this code non-portable, or do
> three out of four compilers surveyed fail to correctly implement K&R?

	Just to stir things up a little, under VAX/VMS, I get an answer
of 839; Turbo C gives an answer of 840!

david@geac.UUCP (David Haynes) (07/08/88)

In article <430@uwovax.uwo.ca> 16012_3045@uwovax.uwo.ca (Paul Gomme) writes:
>In article <133@daitc.ARPA>, jkrueger@daitc.ARPA (Jonathan Krueger) writes:
>> Here's a question of portability and language standards that came up in
>> a real life program.  According to K&R or ANSI, predict the output of
>> the following code:
>> 
>> #define	DEFCONST	1.05
>> main()
>> {
>> 	int	count = 800;
>> 
>> 	printf("count is %d, ", count);
>> 	count *= DEFCONST;
>> 	printf("now %d\n", count);
>> }
>> 
>> My prediction, based on K&R, was the output:
>> 	count is 800, now 839
>> Indeed, the Pyramid 98x produces exactly this output.
>> But your mileage may vary.  4.2BSD VAX, Gould, and Sun-3 produce output:
                               ^^^^^^^^^^
>> 	count is 800, now 800

I don't get this at all! I am running on a VAX 8650 under Ultrix 2.0.
My results are:

cc non-optimized	count is 800, now 839
cc optimized		count is 800, now 839
gcc non-optimized	count is 800, now 839
gcc optimized		count is 800, now 839
vcc non-optimized	count is 800, now 839
vcc optimized		count is 800, now 839

HOWEVER, my sun 3/50 under Sun O/S 3.2 gives the following:

cc non-optimized	count is 800, now 800
cc optimized		count is 800, now 800

As mentioned in the  original article.
yechhh!

>> Which brings me to the question: is this code non-portable, or do
>> three out of four compilers surveyed fail to correctly implement K&R?
>
>	Just to stir things up a little, under VAX/VMS, I get an answer
>of 839; Turbo C gives an answer of 840!


Now, if on the sun, I s/count *= DEFCONST/count = count * DEFCONST/
I get the following:

cc non-optimized	count is 800, now 840
cc optimized		count is 800, now 840

This is even more interesting!

-david-

rob@raksha.eng.ohio-state.edu (Rob Carriere) (07/08/88)

In article <133@daitc.ARPA>, jkrueger@daitc.ARPA (Jonathan Krueger) writes:
> [...] predict the output of the following code:
> #define	DEFCONST	1.05
> main(){
> 	int	count = 800;
> 	printf("count is %d, ", count);
> 	count *= DEFCONST;
> 	printf("now %d\n", count);
> }
> My prediction, based on K&R, was the output: count is 800, now 839
K&R says that ``a*=b'' is eqv to ``a=a*b'' *except* that ``a'' is
evaluated only once.  Sounds like the type cast is not going to be
done => 800 is right.

I don't know about ANSI, I *hope* they changed this; it's horribly
counterintuitive.

Yes, I'm biased; this is what my favorite compiler (Mark Williams C) says.
Rob Carriere

gwyn@brl-smoke.ARPA (Doug Gwyn ) (07/09/88)

In article <374@accelerator.eng.ohio-state.edu> rob@raksha.eng.ohio-state.edu (Rob Carriere) writes:
>K&R says that ``a*=b'' is eqv to ``a=a*b'' *except* that ``a'' is
>evaluated only once.

Yes.

>Sounds like the type cast is not going to be done => 800 is right.

I didn't see any cast operator.  If you mean type conversion,
one IS supposed to be done in order to evaluate a*b where a is
an int and b is a double.  Then the assignment to a should
truncate the double expression value back to an int.

The correct answer is 839 or 840, depending on how precise your
floating-point architecture is.  800 is definitely incorrect.

rob@kaa.eng.ohio-state.edu (Rob Carriere) (07/10/88)

In article <8228@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) 
writes:
>In article <374@accelerator.eng.ohio-state.edu> rob@raksha.eng.ohio-state.edu
>(Rob Carriere) writes: [...]
>>Sounds like the type cast is not going to be done => 800 is right.
>I didn't see any cast operator.  If you mean type conversion,
>one IS supposed to be done in order to evaluate a*b where a is
>an int and b is a double.  Then the assignment to a should
>truncate the double expression value back to an int.

Whoops.  You didn't see it because it isn't there, I *did* mean
conversion.  However, the conversion rule says that a is to be
converted to double; this seems to contradict the idea that a is to be
computed *once*.

Rob Carriere

jfc@athena.mit.edu (John F Carr) (07/12/88)

In article <376@accelerator.eng.ohio-state.edu> 
rob@kaa.eng.ohio-state.edu (Rob Carriere) writes:

>Whoops.  You didn't see it because it isn't there, I *did* mean
>conversion.  However, the conversion rule says that a is to be
>converted to double; this seems to contradict the idea that a is to be
>computed *once*.

I thought the purpose of the definition was so that things like subscripts
and function calls needed to compute the lhs would not be repeated:

 a[f(x++) + --y] += 43;

has different results than

 a[f(x++) + --y]  =  a[f(x++) + --y] + 43;

To make this consistent with the standard, distinguish between "evaluation"
and the type conversions required in computation.

   John Carr             "When they turn the pages of history,
   jfc@Athena.mit.edu     When these days have passed long ago,
                          Will they read of us with sadness
                          For the seeds that we let grow?"  --Neil Peart

chris@mimsy.UUCP (Chris Torek) (07/12/88)

In article <376@accelerator.eng.ohio-state.edu> rob@kaa.eng.ohio-state.edu
(Rob Carriere) writes:
[re int a; ... a *= 1.05;]
>... the conversion rule says that a is to be converted to double; this
>seems to contradict the idea that a is to be computed *once*.

Right idea, wrong expansion: a's *address* (if it has one) is to be
computed once.  (a itself is indeed computed only once: if a is 800 it
is computed/evaluated as 800.  That value, now in a temporary
somewhere, is converted to double, multipled, and stored back in a's
address.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

guy@gorodish.Sun.COM (Guy Harris) (07/13/88)

> >> But your mileage may vary.  4.2BSD VAX, Gould, and Sun-3 produce output:
>                                ^^^^^^^^^^
> >> 	count is 800, now 800
> 
> I don't get this at all! I am running on a VAX 8650 under Ultrix 2.0.

So?  He said "4.2BSD", not "Ultrix 2.0".  4.2BSD and Ultrix 2.0 are different
systems; there's certainly no guarantee that any particular bugs in the 4.2BSD
compiler are also in the Ultrix 2.0 compiler.  One would hope, in fact, that
this would *not* be the case....

I see no reason not to take him at his word here; I presume that he, at least,
is actually *running* 4.2BSD.

> HOWEVER, my sun 3/50 under Sun O/S 3.2 gives the following:
> 
> cc non-optimized	count is 800, now 800
> cc optimized		count is 800, now 800

I believe this is an old PCC bug; the 4.2BSD VAX and Sun compilers are
PCC-based, and the Gould one may be PCC-based as well.  I would not be
surprised if the Pyramid compiler were *not* PCC-based.

My Sun-4/260, and a Sun-3/180 nearby, both running SunOS 4.0, as well as a
not-so-nearby Sun386i running SunOS 4.0RRBETA2, all give

	cc non-optimized	count is 800, now 840
	cc optimized		count is 800, now 840

A 4.3BSD VAX gives

	cc non-optimized	count is 800, now 839
	cc optimized		count is 800, now 839

Presumably the DEC compiler (if it's not the VAX C compiler, in which case you
should get the same results as on VAX/VMS) has had this bug fixed, as have the
4.3BSD compiler and the SunOS compilers.

phil@osiris.UUCP (Philip Kos) (07/20/88)

In article <59649@sun.uucp>, guy@gorodish.Sun.COM (Guy Harris) writes:
> I would not be surprised if the Pyramid compiler were *not* PCC-based.

You're right.  When we got our first Pyramid system here at JHH (January,
1985), OSx cc was was pretty much just vanilla PCC.  This changed in about
mid-1985 as I recall.  Does anyone from Pyramid (Carl?  Sylvan?  Eric?)
want to confirm the date for me?


Phil Kos
A Pretty Happy Pyramid (and soon Sun) User

ihm@nrcvax.UUCP (Ian H. Merritt) (07/29/88)

david@geac.UUCP (David Haynes) says:
	.
	.
	.

>>> Which brings me to the question: is this code non-portable, or do
>>> three out of four compilers surveyed fail to correctly implement K&R?
>>
>>	Just to stir things up a little, under VAX/VMS, I get an answer
>>of 839; Turbo C gives an answer of 840!
>
>
>Now, if on the sun, I s/count *= DEFCONST/count = count * DEFCONST/
>I get the following:
>
>cc non-optimized	count is 800, now 840
>cc optimized		count is 800, now 840
>

Microsoft C also produces the 840 result, suggesting that it's indeed
a rounding issue whether you get 839 or 840, but from the above
substitution, it sure looks like the sun compiler has a bug.  Let's
see now, compiled on my sun (SunOS 3.5 standard distribution), I get:

cc non-optimized	count is 800, now 840
cc optimized		count is 800, now 840

Funny thing, but it's not happening here...

I wonder when this was fixed...

Incidentally, I got the same results on an IS68K bsd unix running very
old software...
	-i

gwyn@brl-smoke.ARPA (Doug Gwyn ) (07/29/88)

In article <376@accelerator.eng.ohio-state.edu> rob@kaa.eng.ohio-state.edu (Rob Carriere) writes:
>However, the conversion rule says that a is to be
>converted to double; this seems to contradict the idea that a is to be
>computed *once*.

That's not the rule.

	a op= b

(where a and b are expressions) is equivalent to

	a = a op b

EXCEPT that the expression a is EVALUATED only once.
I.e. if evaluation of the expression a has side-effects,
they will occur only once.
Once the expression is evaluated, it is used in the context

	a = a op b

and other stuff happens at that point.