guy@auspex.auspex.com (Guy Harris) (07/22/89)
>Sounds like SGI has an unusual argument passing method. Nope. It turned out the problem was that he'd written something like: struct foobar { ... } <<<<<<<<<<<<<NOTE: missing semicolon! main(argc, argv) int argc; char *argv[]; { ... The missing semicolon caused the "struct" declaration to get glued to the definition of "main", so that "main" was being defined as returning a "struct foobar". This presumably changed the calling sequence of "main" in such a way as to scramble the incoming arguments. I've seen this error crop up before; it's certainly easy enough to make. ("For want of a semicolon, the program was lost....") I like to explicitly declare the return type of *all* functions, even those returning "int", and at least in ANSI C (and in most UNIX C implementation) "main" does, in fact, return "int", so I declare it as such. I just realized that doing so can also catch this particular mistake, since, while struct foobar { ... } main(argc, argv) ... is legal (yes, really), struct foobar { ... } int main(argc, argv) ... isn't. So, always declare "main" as returning "int"; it may catch that error someday....
gwollman@tnl.UUCP (Garrett A. Wollman) (07/23/89)
In article <2268@auspex.auspex.com>, guy@auspex.auspex.com (Guy Harris) writes: > Nope. It turned out the problem was that he'd written something like: > > struct foobar { > ... > } <<<<<<<<<<<<<NOTE: missing semicolon! > > main(argc, argv) > int argc; > char *argv[]; > { > ... > > The missing semicolon caused the "struct" declaration to get glued to > the definition of "main"... This presumably changed the calling sequence of > "main" in such a way as to scramble the incoming arguments. > [. . .] It is, of course, obvious, that if we used ANS C-compatible function prototypes, this sort of problem would never get past the compiling stage. For instance, if you had: int main(int,char **); struct foo { int i,j; double k; } main( /* and so on */ The cmompiler would pick up the mismatch. Of course, if you're using prototypes, then your compiler also supports ~voids~ and stuff like that, so you (if you were a careful coder) wouldn't even fall back on this, but get a syntax error right away. I use the type-mismatch trick to help me bring archaic forms up to ANS. I can look through the file and create prototypes for each function, which I put at the beginning of the file. Then, I let the compiler bring me to all the type mismatches, which will be the points where a void function was not declared as void. Saves a lot of time. Actually, the whole business of prototyping saves me a considerable amount of debugging time. This allows me to catch errors such as passing a char to a function which takes an int, when the char was supposed to be unsigned. (Don't think this is a problem? Try writing to a file, using fputc('\xff',fp). The '\xff' will be sign-extended to -1.) -GAWollman -- "(-::-)" (Siamese twins) | "This is a public-access system, so I don't gwollman@tnl.UUCP | know what the operator's opinions are." ...uunet!uvm-gen!tnl!gwollman
gwyn@smoke.BRL.MIL (Doug Gwyn) (07/23/89)
In article <220@tnl.UUCP> gwollman@tnl.UUCP (Garrett A. Wollman) writes:
-Actually, the whole business of prototyping saves me a considerable
-amount of debugging time. This allows me to catch errors such as
-passing a char to a function which takes an int, when the char was
-supposed to be unsigned. (Don't think this is a problem? Try writing
-to a file, using fputc('\xff',fp). The '\xff' will be sign-extended to
--1.)
I don't understand your example: '\xff' is an int, fputc() takes an int.
How is the use of prototypes going to help here? Indeed, why is your
compiler compiling '\xff' as -1?
scs@adam.pika.mit.edu (Steve Summit) (07/29/89)
In article <2268@auspex.auspex.com>, Guy Harris writes: > Nope. It turned out the problem was that he'd written something like: > > struct foobar { > ... > } <<<<<<<<<<<<<NOTE: missing semicolon! > > main(argc, argv) > int argc; > char *argv[]; > { > ... > > The missing semicolon caused the "struct" declaration to get glued to > the definition of "main"... This presumably changed the calling sequence of > "main" in such a way as to scramble the incoming arguments. It occurred to me, the last time or so ago that this problem was discussed, that the compiler could detect it fairly easily, by disparaging the productions struct { struct-decl-list } id (arg-list) decl-list compound-statement and struct tag { struct-decl-list } id (arg-list) ... in favor of struct tag id (arg-list) decl-list compound-statement for declaring functions returning structures. That is, the preferred way to declare a function returning a structure would be (and is!) with a structure tag, referring to a previously- declared structure. An attempt to declare a function within the same declaration in which the shape of the structure was being described would elicit an warning. Implementation of such a feature would be straightforward: in the structure describing a type, a bit could be kept for structure types, recording whether the type had arisen from an explicit structure definition, or implicitly through a structure tag. (This bit would likely have to be kept one level of indirection above the lowest-level structure-describing structure, since type-equivalent structures are often stored exactly once, with equivalence detected by pointer equality.) A function declaration with a return type of "explicit structure" would trigger the message. Obviously, this warning would be appropriate for all functions, not just those named "main." (This error is common because our fingers aren't used to typing semicolons after close-squiggly-braces.) If you think about it, the compiler warning I've suggested could hardly arise accidentally (i.e. from intentionally-written code). The production struct { struct-decl-list } id (arg-list) decl-list compound-statement yields a function that cannot be (correctly) called, since no other object can be declared with a type-equivalent structure. The production struct tag { struct-decl-list } id (arg-list) ... yields a function that can only be called by routines appearing later in the same file. Steve Summit scs@adam.pika.mit.edu
mcdaniel@uicsrd.csrd.uiuc.edu (Tim McDaniel) (07/29/89)
This is cross-posted to comp.lang.c (original article's newsgroup) and comp.std.c (I have standards questions). Followups have been redirected to comp.std.c. In article <13104@bloom-beacon.MIT.EDU> scs@adam.pika.mit.edu (Steve Summit) writes: >The production > > struct { struct-decl-list } id (arg-list) decl-list compound-statement > >yields a function that cannot be (correctly) called, since no >other object can be declared with a type-equivalent structure. I'm not so sure. Separate compilation is allowed in C, but struct tags (and their definitions) are not global in scope; for external linkage, only the types and order of the struct's members matter. I would think the following declarations are strictly conforming: in foo.c: extern struct { int f1; float f2; } func(); ... in bar.c: struct { int a6; float whacky; } func() ... However, K&R 2, 1st edition, p. 213 says A structure or union specifier with a list but no tag creates a unique type; it can referred to directly only in the declaration of which it is a part. >The production > > struct tag { struct-decl-list } id (arg-list) ... > >yields a function that can only be called by routines appearing >later in the same file. This statement is even more problematical. How does it differ from struct tag { struct-decl-list }; struct tag id (arg-list) ... ? If there is no difference, the "struct tag" declaration could just as easily be in an include file, and another file could include it and declare extern struct tag id (); Surely *this* behavior is blessed by the standard. -- "Let me control a planet's oxygen supply, and I don't care who makes the laws." - GREAT CTHUHLU'S STARRY WISDOM BAND (via Roger Leroux) __ \ Tim, the Bizarre and Oddly-Dressed Enchanter \ mcdaniel@uicsrd.csrd.uiuc.edu /\ mcdaniel%uicsrd@{uxc.cso.uiuc.edu,uiuc.csnet} _/ \_ {uunet,convex,pur-ee}!uiucuxc!uicsrd!mcdaniel
scs@adam.pika.mit.edu (Steve Summit) (08/01/89)
In article <1612@garcon.cso.uiuc.edu> mcdaniel@uicsrd.csrd.uiuc.edu (Tim McDaniel) writes: >This is cross-posted to comp.lang.c (original article's newsgroup) and >comp.std.c (I have standards questions). Followups have been >redirected to comp.std.c. Pooh. Now I have to be more careful than I can be, without a copy of the draft at hand... >In article <13104@bloom-beacon.MIT.EDU> scs@adam.pika.mit.edu (Steve >Summit) writes: >>The production >> struct { struct-decl-list } id (arg-list) decl-list compound-statement >>yields a function that cannot be (correctly) called, since no >>other object can be declared with a type-equivalent structure. > >I'm not so sure. Separate compilation is allowed in C, but struct >tags (and their definitions) are not global in scope; for external >linkage, only the types and order of the struct's members matter. It has been suggested that permission to base struct equivalence across files on types and order, rather than the stricter means required within one file, is an exception, reflecting the realities of conventional implementations of separate compilation. The way I think about it is that this is perfectly legal: s.h: struct s {int i;}; a.c: #include "s.h" b.c: #include "s.h" struct s s; extern struct s s; while this is suspect: a.c: struct s {int i;}; b.c: struct s {int i;}; struct s s; extern struct s s; Obviously, a conventional compiler cannot tell these two cases apart, which is why the exception allows the two struct s's in the second example to be considered equivalent. I would not mind it if a smart compiler (or, more preferably, lint) complained about the second form. I have no idea what the chapter and verse of the pANS says on this issue (that's why I'd have kept this in comp.lang.c...). I'm describing a conceptual ideal, based on the obvious stylistic requirement of describing the structure in exactly one place. If the pANS is less stringent (if its permission to base inter-file struct equivalence on type and order is not an exception, as I have suggested, but rather explicit and genuine) then I have no complaint with it, and you don't need to correct me here. (The standard tries to, and should, be pragmatic.) I hope we agree why the first sample code above is vastly preferable to the second. >>The production >> struct tag { struct-decl-list } id (arg-list) ... >>yields a function that can only be called by routines appearing >>later in the same file. > >This statement is even more problematical. How does it differ from > struct tag { struct-decl-list }; > struct tag id (arg-list) ... >? If there is no difference, the "struct tag" declaration could just >as easily be in an include file, and another file could include it... Of course. The difference between struct tag { struct-decl-list } id (arg-list) ... and struct tag { struct-decl-list }; ... struct tag id (arg-list) ... is precisely, and only, that the second form affords more possibilities for equivalent declarations of type "struct tag," especially if the tag is defined in a header file. That is exactly what I was trying to show. I listed three productions: 1. struct { struct-decl-list } id (arg-list) decl-list compound-statement 2. struct tag { struct-decl-list } id (arg-list) ... 3. struct tag id (arg-list) ... and suggested that the first one was, in practice, useless; the second one (theoretically) barely useful; and the third one the only one that would ever appear in real and/or well-written programs. Between the lines is a question, which I'll make explicit: if, in an attempt to catch the common mistake of misdeclaring main (or another function) by leaving out a semicolon after a preceding structure declaration, a compiler were to issue warnings for productions 1. and 2. above, would these warnings be elicited inappropriately for anyone's real programs? (No contrived examples or obfuscated C contest entries, of course.) Steve Summit scs@adam.pika.mit.edu