ok@edai.UUCP (Richard O'Keefe) (02/17/84)
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?
chris@umcp-cs.UUCP (02/21/84)
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
keesan@bbncca.ARPA (Morris Keesan) (02/22/84)
---------------------------- 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
decot@cwruecmp.UUCP (Dave Decot) (02/22/84)
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)