'struct' - declarations & parameters

0 views
Skip to first unread message

Richard O'Keefe

unread,
Feb 16, 1984, 4:25:58 PM2/16/84
to

A couple of days ago I had occasion to port a large C program from
a VAX to an Orion. The C compiler on the Orion was not based on the PCC
but was derived directly from the book and the V7 addendum, then hacked
until all the 4.1bsd programs were correctly compiled.

A note and a question.

The note is that they have two stacks (like the C machine and the
RISC chip) : one for scalars and one for arrays. 'struct' arguments are
passed on the array stack, and struct values returned there. I can find
nothing in the rather sketchy descriptions of C available to forbid this.
Consequently,

struct {int a, b, c;} foo = {1, 2, 3};

main () { printf("%d %d %d\n", foo); }

which works just fine on a VAX, doesn't work on an Orion. I suspect
that it may not work on a RISC chip or on a C70 either. Not only are
structs passed on the array stack. So are unions. I found out the hard
way on the VAX that even when a union fits into 32 bits the PCC still
treats it as a "big" object, so the Orion C compiler is not alone in
treating unions differently from integers etc. The result of that is
that
char xc = 12, *pc = &xc;
double xd = 19.7, *pd = &xd;

void bother(x, i)
union {char *c; double *d;} x;
int i;
{
if (i) {
printf("%d ", *x.c);
} else {
printf("%g\n", *x.d);
}
}

void main()
{
bother(pc, 1);
bother(pd, 0);
}

doesn't work either. pc and pd are pointers, so get passed on the
scalar stack, while x is a union, so is looked for on the array stack.
Once again, this doesn't seem to be forbidden by available descriptions
of C, and is likely to happen on other "C machines".

The question is whether the final semicolon in a 'struct'
declaration is optional or not. I have been using two layouts for
structures:

typedef struct foo
{
type1 field1; /* rem1 */
...
typen fieldn; /* remn */
} foo;

for important types; and for tiny little structs embedded in something:

struct {type1 field1; ...; typen fieldn} dummy;

both of which the VAX C compiler is perfectly happy with. But the Orion
compiler, being written from the book, insists on the amazingly ugly ;}
in both cases. Which compiler is right?

ch...@umcp-cs.uucp

unread,
Feb 20, 1984, 5:34:23 PM2/20/84
to
Well first off, writing

struct { int i, j, k; } foo = { 1, 2, 3 };

main () { printf ("%d %d %d\n", foo); }

is just plain illegal. The bit about unions is also illegal. If you
must pass a union, do something like

union xyzzy { char *c; int i; };
main () {
char *s;
...
{
union xyzzy temp;
temp.c = s;
strange (temp, 1);
}
...
}

(This should be lots of fun for me: Gosling Emacs uses that union
trick for the first parameter to DefMac. *Sigh*)

As to whether the trailing semicolon is required in structure
declarations: all I can say is it doesn't hurt to use it. (Though
if you want type declarations to match function declarations, it
should be optional. I don't have to write "dummy () { ; }".)
--
In-Real-Life: Chris Torek, Univ of MD Comp Sci
UUCP: {seismo,allegra,brl-bmd}!umcp-cs!chris
CSNet: chris@umcp-cs ARPA: chris.umcp-cs@CSNet-Relay

Morris Keesan

unread,
Feb 21, 1984, 5:54:31 PM2/21/84
to
----------------------------

It looks like the Orion compiler wins in all three cases. The last case is
the simplest. The C Reference Manual is very clear that the declaration for
each member of a structure requires a ';' at the end of it, so in this case the
Orion compiler is clearly right, and the VAX compiler you're using is in
violation of the language definition.

The other two cases are not quite so straightforward. Both compilers are
behaving in completely legal fashion, since the language definition says nothing
about how argument passing is to be implemented (except that the semantics are
"call by value"). The source code is at fault here, since it was written to
expect the implementation of the calling sequence which is provided by the
VAX compiler (and similar compilers).
Passing a structure as if it were three integers runs you right into the
"varargs" problem. From page 71 of K&R:

By the way, there is no entirely satisfactory way to write a
portable function that accepts a variable number of arguments, because
there is no way for the called function to determine how many arguments
were passed to it in a given call. . . .
It is generally safe to deal with a variable number of arguments if
the called function doesn't use an argument which was not actually
supplied, and if the types are consistent. printf . . . fails badly if
the caller does not supply enough arguments or if the types are not
what the first argument says.

This suggests that

> struct {int a, b, c;} foo = {1, 2, 3};
> main () { printf("%d %d %d\n", foo); }

is bogus and should never have been coded that way. Your second example,
passing pointers as if they were unions, is clearly illegal because of type
mismatch between the formal and actual parameters. Lint should have
complained about this. Assuming you know enough about the target machine
and the compiler implementation to know that (char *) and (double *) are
the same size, and that a union of the two is also that size, the slightly
more portable way of coding your second example would be

union foo {char *c; double *d;};

void bother(x,i)
union foo x; int i;
{ . . .
}

void main()
{
bother((union foo)pc, 1);
bother((union foo)pd, 0);
}

but this is still non-portable and not guaranteed to work (if, for example,
char pointers are a different size from other pointers).

Incidentally, both of these rather bogus code samples work okay on a C70,
although the second one won't work with the "void" declarations until my newer
version of the compiler is released.
--
Morris M. Keesan
{decvax,linus,wjh12,ima}!bbncca!keesan
keesan @ BBN-UNIX.ARPA

Dave Decot

unread,
Feb 21, 1984, 9:33:57 PM2/21/84
to
Chris Torek says:

...writing

struct { int i, j, k; } foo = { 1, 2, 3 };

main () { printf ("%d %d %d\n", foo); }

is just plain illegal.

This code is NOT illegal, nor is it illegal to pass unions. It is only
non-portable (but lint(1) has no complaint, because the problem is in
printf). In fact, it usually works (for example, on our VAX, 4.1bsd). Some
recent changes to C allow you to pass structures and unions as parameters to
functions. If your compiler has no `enum' types, then it is outdated, and
probably doesn't support struct/union parameter passing.

As to whether the trailing semicolon is required in structure
declarations: all I can say is it doesn't hurt to use it. (Though
if you want type declarations to match function declarations, it
should be optional. I don't have to write "dummy () { ; }".)

It isn't, and should not be, optional. The VAX compiler doesn't signal this
as a syntax error, but it should, since it is. The fact that you need no
semicolon in a dummy function body is no demonstration of inconsistency,
it is a demonstration of consistency. Statements in C are *terminated*
(not separated, as in Pascal) by a semicolon. It is only natural that every
declaration (including field declarations) must also be terminated by a
semicolon.

The function body in

dummy () { ; }

is allowed and interpreted as a null statement, but in

dummy () { }

there is no statement (since none are required), and thus no ; is needed.

Dave Decot "Non-Americans are people, too."
decvax!cwruecmp!decot (Decot.Case@rand-relay)

ch...@umcp-cs.uucp

unread,
Feb 22, 1984, 4:48:14 AM2/22/84
to
*Sigh*...

From: de...@cwruecmp.UUCP (Dave Decot)

Chris Torek says:

...writing

struct { int i, j, k; } foo = { 1, 2, 3 };

main () { printf ("%d %d %d\n", foo); }

is just plain illegal.

This code is NOT illegal, nor is it illegal to pass unions.

It is *syntactically* correct. It is *semantically* wrong. That,
as far as I am concerned, makes it illegal. I also consider passing
0 instead of (type *)0 as a paramter to be illegal. Perhaps "bogus"
is a better word.

Reply all
Reply to author
Forward
0 new messages