[net.bugs.4bsd] Bug in 4.2BSD C compiler...

mcbryan@cmcl2.UUCP (Oliver A. McBryan) (06/03/84)

/*
*			BUG in 4.2 BSD C Compiler:
*
*	The following program succeeds on the first test, fails on 
*	the second which should be identical.
*
*	Both tests succeed if either
*		(a) every float is changed to double
*	or
*		(b) p.x is assigned to instead of p.y
*
*/

#include <stdio.h>

struct POINT {
	float	x;
	float	y;
};

main()
{
	struct POINT p, *q;
	float	f;

	p.y = 0.1;
	f = 1.0;

	if (p.y < (f-.01))  printf("p: %g is < %g\n",p.y,f-.01);

	q = &p;
	if (q->y < (f-.01))  printf("q: %g is < %g\n",q->y,f-.01);
}

thomas@utah-gr.UUCP (Spencer W. Thomas) (07/16/84)

Index:	lib/ccom 4.2BSD

Description:
	When casting an unsigned bit field to a signed integer, sign extension
	is done.

Repeat-By:
	cc -S the following program.  Note the ext instructions.  Note also that
	this problem does not appear for full size unsigned ints.

main()
{
	int i;
	unsigned short j;
	struct {
		unsigned int a : 3;
	} a;

	i = a.a;
	i = (int)a.a;
	i = j;
	i = (int)j;
}
The (edited) output follows:

_main:
	extzv	$0,$3,_a,-4(fp)
	extv	$0,$3,_a,-4(fp)
	movzwl	-6(fp),-4(fp)
	movzwl	-6(fp),-4(fp)
	ret

jss@sjuvax.UUCP (J. Shapiro) (05/09/85)

About two days ago I posted an article complaining that the following compiled
incorrectly under 4.2:

int usr1(), usr2(), usr3();

int procs[] = { usr1, usr2, usr3 }

Of course it doesn't compile, but I mistyped what I wanted. Several
people sent suggestions, and my thanks to all of them.  The piece of code
which doesn't compile and should is as follows:

---- correctly typed version ----

int usr1(), usr2(), usr3();

int *procs[] = { usr1, usr2, usr3 };

---------------------------------

Now, several people observed that

int (*procs[])() = ...

will work, and this is correct.  The question arises on the basis of K&R
pp 114-115, which would seem to indicate that my declaration is acceptable
on the grounds that pointers to integers and pointers to functions returning
integers are supposed to be equationally indistinguishable.

Would someone be good enough to try this on System V and tell me if the silly
thing typed correctly compiles?

I don't want to make this a religious battle - I will use what works, but it
did strike me as curious that three of the four C compilers I use regularly
take this without complaint, and that the loser was 4.2BSD. Is this version
right or wrong?

Thanks....

henry@utzoo.UUCP (Henry Spencer) (05/09/85)

> ...  The question arises on the basis of K&R
> pp 114-115, which would seem to indicate that my declaration is acceptable
> on the grounds that pointers to integers and pointers to functions returning
> integers are supposed to be equationally indistinguishable.

I don't know how you got this idea; nothing of the sort appears on pages
114-115 of my copy of K&R.  The only thing there that is even vaguely along
these lines is the observation that function names don't need an & since
the compiler knows they are functions.  They still remain pointers to
functions, not pointers to integers.

Compilers that accept either of your versions are being sloppy.  There
are many sloppy C compilers in the world.  Do not mistake this for
sloppiness in the language.  "int (*foo[])() = {...}" remains the right
way to declare an array of pointers to functions returning int.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

david@ukma.UUCP (David Herron, NPR Lover) (05/09/85)

In article <1141@sjuvax.UUCP>, jss@sjuvax.UUCP (J. Shapiro) writes:
> Now, several people observed that
> 
> int (*procs[])() = ...
> 
> will work, and this is correct.  The question arises on the basis of K&R
> pp 114-115, which would seem to indicate that my declaration is acceptable
> on the grounds that pointers to integers and pointers to functions returning
> integers are supposed to be equationally indistinguishable.
You should turn the page to #116.  Look at the declaration for sort()
which I'll go ahead and quote:

	sort(v, n, comp, exch)
	char *v[];
	int n;
	int (*comp)(), (*exch)();
	{
		...
	}

And they say to pay specific attention to the () around *comp.

What is happening is they (K&R) are playing a little loose with the rules.
Sure, at the call, the compiler hasn't yet seen the declaration, so the
parameters all default to ints.  But that doesn't work for all compilers
on all systems.  

The best thing to do is to declare everything PROPERLY, do all the casts
your supposed to, etc.  Then you get caught by silly things like compilers
which don't have void, and don't allow typedefs to void.

> 
> Would someone be good enough to try this on System V and tell me if the silly
> thing typed correctly compiles?

I tried it on System Vr2 on a 3B2.  It don't work.  Like it shouldn't

> I don't want to make this a religious battle - I will use what works, but it
> did strike me as curious that three of the four C compilers I use regularly
> take this without complaint, and that the loser was 4.2BSD. Is this version
> right or wrong?

This version is most correct.  Run your code through lint.  It'll complain
about too many things, but it'll give you something to look think about.
-- 
--- David Herron
--- ARPA-> ukma!david@ANL-MCS.ARPA or ukma!david<@ANL-MCS> 
---	   or david%ukma.uucp@anl-mcs.arpa
---        Or even anlams!ukma!david@ucbvax.arpa
--- UUCP-> {ucbvax,unmvax,boulder,oddjob}!anlams!ukma!david
---        {ihnp4,decvax,ucbvax}!cbosgd!ukma!david

	"It's *Super*User* to the rescue!"

ed@mtxinu.UUCP (Ed Gould) (05/11/85)

>                                  The question arises on the basis of K&R
> pp 114-115, which would seem to indicate that my declaration is acceptable
> on the grounds that pointers to integers and pointers to functions returning
> integers are supposed to be equationally indistinguishable.

??? I sure don't read it that way.  What you may be misreading is that
a declaration of a function, e.g.

	int funct();

is in effect declaring funct to be, in some semantic equivalency sort of way,
to be a pointer to a function.  The sequence

	f() {
	    int f2();
	    int (*f3)();

	    f3 = f2;
	    (*f3)();
	}

is reasonable and legal; the sequence

	f() {
	    int f2();
	    int *f3();

	    f3 = f2;
	    (*f3)();
	}

makes no real sense.  The key is that () binds tighter than *.  Of course,

	*f3();

(assuming that f3 is a function returning a pointer) is also reasonable,
but has *very* different meaning.

-- 
Ed Gould		    mt Xinu, 2910 Seventh St., Berkeley, CA  94710  USA
{ucbvax,decvax}!mtxinu!ed   +1 415 644 0146