ptf@cs.bham.ac.uk (Paul Flinders <FlindersPT>) (10/30/90)
Can anbody suggest an elegant solution to the following. given the file foo.c which contains code for a module within a program, foo.h which defines prototypes for routines in foo.c and bar.c which includes foo.h I tend to include foo.h in foo.c so that the compiler will tell me if I have been foolish enough to change a routines parameters without changing foo.c (the code in foo.c is not yet cast in stone so changes are a posibility). This works fine _except_ for varargs functions eg. in foo.h: extern void ddprintf(const char *fmt, ...); BUT in foo.c: void ddprintf(va_alist) va_dcl; this causes problems. The only solution that I've thought of is to define some preprocessor token in foo.c _before_ the include of foo.h and then #ifdef the extern declaration out. This seems a little messy though. Anybody else have any solutions to this. Paul Flinders | "It is bad luck to be superstitious." FlindersPT@cs.bham.ac.uk | -- Andrew W. Mathis
jtc@van-bc.wimsey.bc.ca (J.T. Conklin) (10/30/90)
In article <1005@christopher-robin.cs.bham.ac.uk> ptf@uk.ac.bham.cs (Paul Flinders <FlindersPT>) writes: > >This works fine _except_ for varargs functions eg. > >in foo.h: > extern void ddprintf(const char *fmt, ...); > >BUT in foo.c: > > void ddprintf(va_alist) > va_dcl; You seem to be using the old style <varargs.h> interface which is not compatible with prototypes. Try something like #include <stdarg.h> void ddprintf(const char *fmt, ...) { va_list args; va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); } --jtc -- J.T. Conklin UniFax Communications Inc. ...!{uunet,ubc-cs}!van-bc!jtc, jtc@wimsey.bc.ca
steve@taumet.com (Stephen Clamage) (10/31/90)
ptf@cs.bham.ac.uk (Paul Flinders <FlindersPT>) writes: >given the file foo.c which contains code for a module within a program, >foo.h which defines prototypes for routines in foo.c and bar.c which >includes foo.h I tend to include foo.h in foo.c so that the compiler >will tell me if I have been foolish enough to change a routines >parameters without changing foo.c (the code in foo.c is not yet cast >in stone so changes are a posibility). This works fine _except_ for >varargs functions eg. >in foo.h: > extern void ddprintf(const char *fmt, ...); >BUT in foo.c: > void ddprintf(va_alist) > va_dcl; >this causes problems. As well it should. What you show is not ANSI C, despite the Subject line of your posting. It is the BSD C approach to variadic functions, which is not quite the same as the ANSI approach. In ANSI C, void ddprintf(const char *fmt, ...); and void ddprintf(va_alist); are not at all the same. It sounds like you are using <varargs.h> with an ANSI compiler, instead of using <stdarg.h>. If you use the ANSI C <stdarg.h> header, the function delcaration in foo.h and the function defintion in foo.c become identical. But you need to decide if the function is to take a variable *list* of arguments, or *one* argument of type va_list. The two notions are not the same. Refer to the discussions of <stdarg.h>, printf() and vprint() in any good ANSI C text, or in the Standard, for more details. -- Steve Clamage, TauMetric Corp, steve@taumet.com
stanley@phoenix.com (John Stanley) (10/31/90)
ptf@cs.bham.ac.uk (Paul Flinders <FlindersPT>) writes: > Can anbody suggest an elegant solution to the following. > > in foo.h: > extern void ddprintf(const char *fmt, ...); > > BUT in foo.c: > > void ddprintf(va_alist) > va_dcl; > > this causes problems. The only solution that I've thought of is to > define some preprocessor token in foo.c _before_ the include of foo.h > and then #ifdef the extern declaration out. This seems a little messy > though. Anybody else have any solutions to this. There are two simple solutions: 1) Use a VAX. VMS C does not (at least, did not) care about the extern missing from extern declarations. This means the same include that defines a global int i may be included in all files. The linker on VMS happily ignores multiple definitions and layers everything with the same name to the same address. 2) Do what you thought of. It is pretty common, in my experience, that the main routine has a #define MAIN, with the included files having: #ifndef MAIN #define EXTERN #else #define EXTERN extern #endif This way, all global variables get defined in the main routine, and declared in the rest. You probably could just #define extern to nothing, but that would screw up any externs in any files follwing that one. "Arinth is a beautiful planet." "Oh, have you been there?" "Yes, but not yet." The Doctor. (TB)
boyd@necisa.ho.necisa.oz (Boyd Roberts) (10/31/90)
In article <1005@christopher-robin.cs.bham.ac.uk> ptf@uk.ac.bham.cs (Paul Flinders <FlindersPT>) writes: > >in foo.h: > extern void ddprintf(const char *fmt, ...); > >BUT in foo.c: > > void ddprintf(va_alist) > va_dcl; > >this causes problems. Right on! The function prototypes are just stupid. I shouldn't have to go: extern gore *good(const char *vomit); to get the functionality of type checking of function arguments. The compiler and loader should do it. The computer is there to do the tedious stuff for you. The computer is (was) your friend. There should be enough stuff in the `.o' to specify all the calls to my function good() complete with the types of all the arguments. The `.o' that contains good() should contain extra information of the types of the arguments to good(). Then the loader should cross check all the calls with the declaration and then _refuse_ to load unless everything check out just right. Yes, that's right -- _refuse_. Now this would remove function prototyping once and for all. But, before you say `what about var args'. Things that are var arged should be specified as such on the command line. You say how many arguments to check. Now, I've seen it done and it's good. My old mate brucee did it `back in the hippy days' and it runs at the Labs. Ever heard of `cyntax'? Check out cyntax(1) in the Ninth Edition manual. Boyd Roberts boyd@necisa.ho.necisa.oz.au ``When the going gets wierd, the weird turn pro...''
rjc@uk.ac.ed.cstr (Richard Caley) (11/01/90)
In article <1906@necisa.ho.necisa.oz> boyd@necisa.ho.necisa.oz (Boyd Roberts) writes:
Right on! The function prototypes are just stupid. I shouldn't have to go:
extern gore *good(const char *vomit);
to get the functionality of type checking of function arguments.
The compiler and loader should do it.
Ok, so what happens to code which never sees the loader?
I want my errors when I compile things, not when some poor guy tries
to use it.
Even in less extreme cases, having the loader do all the checking
would mean you got no error checking until you did a full compile and
link. For even fairly small programs that will be unacceptable ``Well,
yeah, we really do need the cray, we have to recompile the entire
system every three minutes during development.''
Which is not to say that the linker shouldn't _also_ check the types.
So should the run time system and the disc driver, if I had my way :-)
--
rjc@uk.ac.ed.cstr Paranoid of Leith
salomon@ccu.umanitoba.ca (Dan Salomon) (11/02/90)
In article <RJC.90Nov1145211@brodie.uk.ac.ed.cstr> rjc@uk.ac.ed.cstr (Richard Caley) writes: >In article <1906@necisa.ho.necisa.oz> boyd@necisa.ho.necisa.oz (Boyd Roberts) writes: > > > Right on! The function prototypes are just stupid. > > I shouldn't have to type: > > extern gore *good(const char *vomit); > > to get the functionality of type checking of function arguments. > > The compiler and loader should do it. > > I want my errors when I compile things, not when some poor guy tries > to use it. > You are both right. Repeatedly typing function prototypes is a tedious waste of time, but we really would like type errors reported at compile time. A possible solution would be to have a utility for building libraries of function prototypes from source code. The compiler could check source code usage against usage in this library. The linker would have to repeat the check to make sure that the prototype library didn't get out of synch with the object library. -- Dan Salomon -- salomon@ccu.UManitoba.CA Dept. of Computer Science / University of Manitoba Winnipeg, Manitoba, Canada R3T 2N2 / (204) 275-6682
peter@ficc.ferranti.com (Peter da Silva) (11/03/90)
In article <1990Nov2.030556.27759@ccu.umanitoba.ca> salomon@ccu.umanitoba.ca (Dan Salomon) writes: > You are both right. Repeatedly typing function prototypes is a tedious > waste of time, but we really would like type errors reported at compile > time. Ever hear of include files? > A possible solution would be to have a utility for building libraries > of function prototypes from source code. The Manx compiler for the Amiga has a flag that lets you build include files from the source. -- Peter da Silva. `-_-' +1 713 274 5180. 'U` peter@ferranti.com
stever@Octopus.COM (Steve Resnick ) (11/03/90)
In article <1990Nov2.030556.27759@ccu.umanitoba.ca> salomon@ccu.umanitoba.ca (Dan Salomon) writes: >In article <RJC.90Nov1145211@brodie.uk.ac.ed.cstr> rjc@uk.ac.ed.cstr (Richard Caley) writes: >>In article <1906@necisa.ho.necisa.oz> boyd@necisa.ho.necisa.oz (Boyd Roberts) writes: >> >> > Right on! The function prototypes are just stupid. >> > I shouldn't have to type: >> > extern gore *good(const char *vomit); >> > to get the functionality of type checking of function arguments. >> > The compiler and loader should do it. >> >> I want my errors when I compile things, not when some poor guy tries >> to use it. >> > >You are both right. Repeatedly typing function prototypes is a tedious >waste of time, but we really would like type errors reported at compile >time. > >A possible solution would be to have a utility for building libraries >of function prototypes from source code. The compiler could check >source code usage against usage in this library. The linker would have >to repeat the check to make sure that the prototype library didn't get >out of synch with the object library. >-- > Some C compilers do this for you. Microsoft C 6.0 will, as an option generate declarations (prototypes) to stdout when asked to. This has saved me the tedium of typing all those prototypes in myself! :) Cheers! Steve -- ---------------------------------------------------------------------------- steve.resnick@f105.n143.z1.FIDONET.ORG - or - apple!camphq!105!steve.resnick Flames, grammar errors, spelling errrors >/dev/nul The Asylum OS/2 BBS - (408)263-8017 IFNA 1:143/105.0
salomon@ccu.umanitoba.ca (Dan Salomon) (11/03/90)
In article <MKU65ZE@xds13.ferranti.com> peter@ficc.ferranti.com (Peter da Silva) writes: >In article <1990Nov2.030556.27759@ccu.umanitoba.ca> salomon@ccu.umanitoba.ca (Dan Salomon) writes: >> You are both right. Repeatedly typing function prototypes is a tedious >> waste of time, but we really would like type errors reported at compile >> time. >> A possible solution would be to have a utility for building libraries >> of function prototypes from source code. > >Ever hear of include files? > Actually, include files aren't quite the same as a library of function prototypes. The distinction is the same as between an object library, and a file full of object modules. In addition to the problem of keeping the include files up to date, there is also the problem of filling up your symbol table with dozens of unused symbols. Processing all the prototypes in an include file is slower than a search for and processing of only the ones actually needed. This is especially a problem when a large collection of functions are grouped together in a common directory, but in separate files. Such an organization speeds up the compilation of large projects, by allowing the recompilation of only the out-of-date functions. If each of the files has to include a large number of prototypes, the some of the speed up is lost. Once your set of functions is running, what tool do you use to assemble all the prototypes into up-to-date include files? Such tools exists for object modules, perhaps similar tools are needed for function prototypes. -- Dan Salomon -- salomon@ccu.UManitoba.CA Dept. of Computer Science / University of Manitoba Winnipeg, Manitoba, Canada R3T 2N2 / (204) 275-6682
rjc@uk.ac.ed.cstr (Richard Caley) (11/03/90)
In article <1990Nov2.030556.27759@ccu.umanitoba.ca> salomon@ccu.umanitoba.ca (Dan Salomon) writes: In article <RJC.90Nov1145211@brodie.uk.ac.ed.cstr> rjc@uk.ac.ed.cstr (Richard Caley) writes: > I want my errors when I compile things, not when some poor guy tries > to use it. You are both right. Repeatedly typing function prototypes is a tedious waste of time, but we really would like type errors reported at compile time. Since there is, as far as I know, no difference between the prototype and the definition except for the `;', there is no extra typing to do. Just copy the definition. Now I realise there are some brain dead editors out there and I have upon occasion written C using `cat', but I assume that anything anyone is willing to use for more than trivial coding can manage a textual copy. -- rjc@uk.ac.ed.cstr
peter@ficc.ferranti.com (Peter da Silva) (11/04/90)
In article <1990Nov3.122432.24738@ccu.umanitoba.ca> salomon@ccu.umanitoba.ca (Dan Salomon) writes: > Actually, include files aren't quite the same as a library of function > prototypes. The distinction is the same as between an object library, > and a file full of object modules. True, there is an efficiency consideration. I don't tend to have a single module or collection of modules that require more than a handful of files, so this hasn't been a problem. Plus, who says include files have to be stored in files? The C standard doesn't. This is an implementation detail. :-> Yeh, it's a problem, but it's not a show stopper. > In addition to the problem of > keeping the include files up to date, That is the real problem. You need a tool to extract the prototypes from a file. Beyond that, make will do the rest. > Processing all the prototypes in an include file is slower than a search > for and processing of only the ones actually needed. Precompiled include files. Some compilers have 'em. I've never had to use 'em myself, but my home machine has plenty of MIPs and IoStones. -- Peter da Silva. `-_-' +1 713 274 5180. 'U` peter@ferranti.com
Markku.Savela@tel.vtt.fi (Markku Savela) (11/04/90)
In article <-BV6Q16@xds13.ferranti.com> peter@ficc.ferranti.com (Peter da Silva) writes: >> In addition to the problem of >> keeping the include files up to date, >That is the real problem. You need a tool to extract the prototypes from >a file. Beyond that, make will do the rest. Yes, but this is a bad habit. The include file should be the external specification of the module. Any changes in external specification shouldn't be so frequent, if you have the code done right. -- Markku Savela (savela@tel.vtt.fi), Technical Research Centre of Finland Telecommunications Laboratory, Otakaari 7 B, SF-02150 ESPOO, Finland
jaakola@cc.helsinki.fi (11/05/90)
In article <RJC.90Nov3153129@brodie.uk.ac.ed.cstr>, rjc@uk.ac.ed.cstr (Richard Caley) writes: > Since there is, as far as I know, no difference between the prototype > and the definition except for the `;', there is no extra typing to do. > Just copy the definition. Why do *I* have to do the copying for all my functions, while there's the compiler which a) is supposed to work for me and not vice versa and b) should know ANSI peculiarities better than I do? It's okay for me to make an include file, where I declare functions that are visible to other modules. But consider the following example: static void auxiliary_func(a) /* private helper-function */ int a; { ... } void visible_fun(b) int b; { ... auxiliary_func(b+1); /* should be checked */ ... } The point is, why should I have to tell the compiler twice the type of auxiliary_func? The prototype should be necessary only if I make a forward reference to make it easier for the compiler to check types in a single pass. I think the function definition tells unambiguously the types, so I should not have to watch warnings such as "function definition used as a prototype" (Microsoft C 5.1). Ok, I could turn off such warnings in Microsoft C 5.1, but this turns off some useful checks as a side-effect! Please, Microsoft, make a "prototypes-off" switch into Microsoft C for me! I do not want to bother keeping prototypes of such axiliary helper-functions up-to-date. "You could use an automatic prototype builder," I hear you say. Yeah, I could, but why couldn't that builder be built into the compiler, so that I didn't have to burden my brains to use it? After all, those helper-functions tend to change much when I fine-tune the implementation of my module. Another ANSI-misfeature is the ability to make declarations such as: int foo(int b, char *s) I like much more the old style int foo(b,s) int b; /* the b means ... blahblahblah */ char *s; /* the s means ... */ This is better, because you can have function name and args on the same line, so that you can query all function names by grep-like tools (grep outputs only single lines, which is very compact and - I think - readable format). If you have much args, this way you can still put all of them on a single line. After the first line I tell the types of each arg and use comments after each args as shown above.
hurtta@cs.Helsinki.FI (Kari Hurtta) (11/05/90)
In article <3933.27353319@cc.helsinki.fi> jaakola@cc.helsinki.fi writes: It's okay for me to make an include file, where I declare functions that are visible to other modules. But consider the following example: static void auxiliary_func(a) /* private helper-function */ int a; { ... } void visible_fun(b) int b; { ... auxiliary_func(b+1); /* should be checked */ ... } The point is, why should I have to tell the compiler twice the type of auxiliary_func? The prototype should be necessary only if I make a forward reference to make it easier for the compiler to check types in a single pass. I think the function definition tells unambiguously the types, so I should not have to watch warnings such as "function definition used as a prototype" (Microsoft C 5.1). Ok, I could turn off such warnings in Microsoft C 5.1, but this turns off some useful checks as a side-effect! Please, Microsoft, make a "prototypes-off" switch into Microsoft C for me! Why not: static void auxiliary_func(int a) { ... } void visible_fun(int b) { ... auxiliary_func(b+1); ... } - K E H ( hurtta@cc.Helsinki.FI hurtta@cs.Helsinki.FI HURTTA@FINUH.BITNET )
mcdaniel@adi.com (Tim McDaniel) (11/06/90)
Markku.Savela@tel.vtt.fi (Markku Savela) writes: > Any changes in external specification shouldn't be so frequent, if > you have the code done right. You assume (1) that there is a "right" way to do a module for a project; (2) that that "right" way is determinable before it is coded; (3) that the programmer can determine this "right" way a priori. Assumption (2) fails at my workplace. I've done a dozen or two little tweaks to the major module I've developed: a variable exported here, an argument type changed there, et cetera. I didn't know that we'd want to ship exceptions across the network. Nor did I know that someone needed VAXC$ERRNO. An automatic exporter tool is a great convenience, because I don't have to worry about keeping the .h up to date with the .c. I have a hard time just remembering to comment out the #define STANDALONE_DEBUG before checking it in! It is particularly nice here, because the tool does a "diff" between the new .h and the old one, and if they're the same, deletes the new one and leaves the old one untouched. Unnecessary makes are avoided even when you "mig *.c" to check everything. By the way, a compiler option to output prototypes is not useful. It should output declarations for all external identifiers, and only those. -- Tim McDaniel Applied Dynamics Int'l.; Ann Arbor, Michigan, USA Work phone: +1 313 973 1300 Home phone: +1 313 677 4386 Internet: mcdaniel@adi.com UUCP: {uunet,sharkey}!amara!mcdaniel
peter@ficc.ferranti.com (Peter da Silva) (11/06/90)
In article <3933.27353319@cc.helsinki.fi> jaakola@cc.helsinki.fi writes: > static void auxiliary_func(a) /* private helper-function */ > int a; > { > ... > } If you do this: static void auxilary_func(int a) { ... } Everything will work fine. You only need declare it once. Just do it right the first time and you won't have to do it again (my father always used to tell me that). -- Peter da Silva. `-_-' +1 713 274 5180. 'U` peter@ferranti.com
rmartin@clear.com (Bob Martin) (11/06/90)
In article <1906@necisa.ho.necisa.oz> boyd@necisa.ho.necisa.oz (Boyd Roberts) writes: > > Right on! The function prototypes are just stupid. I shouldn't have to go: > > extern gore *good(const char *vomit); > > to get the functionality of type checking of function arguments. > The compiler and loader should do it. > The C++ compiler does this. If you declare a function one way and use it in another, say with different type arguments, then the program won't link. C++ does this by mangling the return type and argument types into the function name. Thus when you declare a function: int x(int y) the compiler generates a new name for the function which is what the loader sees. This name would specify that the function's name was x, that it returned an int and that it had a single int parameter. So if you screw up your declarations, or attempt to use implicit declarations (bad style), you cannot get a runtime error becuase of a type mismatch. The linker will catch the problem. -- By the way, this technique of mangling the function names means that int x(int y); and double x(double y); are completely different functions. You can declare both of them, define them separately and call the proper function by making sure that the types are correct. +----------------------+---------------------------------------------+ | Robert C. Martin | The authors opinions are his own and do not | | rmartin@clear.com | represent the opinions of his employer. | | uunet!clrcom!rmartin | | +----------------------+---------------------------------------------+ -- +----------------------+---------------------------------------------+ | Robert C. Martin | The authors opinions are his own and do not | | rmartin@clear.com | represent the opinions of his employer. |
rjc@uk.ac.ed.cstr (Richard Caley) (11/06/90)
In article <3933.27353319@cc.helsinki.fi> jaakola@cc.helsinki.fi writes: It's okay for me to make an include file, where I declare functions that are visible to other modules. But consider the following example: static void auxiliary_func(a) /* private helper-function */ int a; { ... } void visible_fun(b) int b; { ... auxiliary_func(b+1); /* should be checked */ ... } The point is, why should I have to tell the compiler twice the type of auxiliary_func? You don't. In the above case you havn't even told it once. If you did... static void auxiliary_func(int a) { ... } you wouldn't need to type anything more. Or if you did that would be a massive compiler misfeature. This even saves you a couple of characters :-) Ok, I could turn off such warnings in Microsoft C 5.1, but this turns off some useful checks as a side-effect! Please, Microsoft, make a "prototypes-off" switch into Microsoft C for me! If the compiler really does complain in the case where you give the full type in the function definition then I agree that the writers had better start watching out for mobs of irate users coming after them with pitchforks and flaming torches. Someone must make a working C compiler for your machine... -- rjc@uk.ac.ed.cstr
chris@mimsy.umd.edu (Chris Torek) (11/06/90)
>In article <1005@christopher-robin.cs.bham.ac.uk> ptf@cs.bham.ac.uk >(Paul Flinders <FlindersPT>) writes: >>[my foo.h contains >> extern void ddprintf(const char *fmt, ...); >> and my foo.c contains >> void ddprintf(va_alist) >> va_dcl; >> and so I get an error]. The only solution that I've thought of is to >>define some preprocessor token in foo.c _before_ the include of foo.h >>and then #ifdef the extern declaration out. In article <BPaVR3w161w@phoenix.com> stanley@phoenix.com (John Stanley) provides a correct answer to a completely different question: > 1) Use a VAX. VMS C does not (at least, did not) care about the extern >missing from extern declarations. This means the same include that >defines a global int i may be included in all files. This refers to object declarations / definitions, as opposed to function declarations / definitions. VAX/VMS C uses the same model that most modern systems use, in which int foo; means: `There is an object called foo which is declared the same way in some other source file(s), possibly but not necessarily with ``extern'' added on the front.' (This is also known as `the common model' since it implements FORTRAN's named COMMON blocks.) Other systems, however, treat the above as both a declaration and a definition: `There is an object called foo. This is it. This is the only one.' On these systems writing `extern int foo;' means: `There is an object called foo. This is not it. Get me that object.' (This is also known as the `def/ref' model: a declaration without `extern' is a DEFinition, while one with `extern' is a REFerence, and there must be exactly one definition for everything.) The def/ref model is all that is required of a C system. Some find the common model more convenient; some find it more error-prone; since FORTRAN virtually requires it, most systems have it, but sometimes in a very limited form. John Stanley goes on to provide an incorrect answer (but one which, if interpreted in the context of the question answered above, becomes correct): > 2) Do what you thought of. It is pretty common, in my experience, that >the main routine has a #define MAIN, with the included files having: > > #ifndef MAIN > #define EXTERN > #else > #define EXTERN extern > #endif > >This way, all global variables get defined in the main routine, and >declared in the rest. This works fine for variables, but is not correct for function prototypes (more on this in a moment). >You probably could just #define extern to nothing, >but that would screw up any externs in any files follwing that one. Well, you can then `#undef extern'. A more likely problem is that many compilers refuse to allow `#define'ing anything that resembles a keyword (incorrectly, by ANSI X3.159-1989, since keywords do not exist during the preprocessing phase of the translation). Okay, so what is wrong with: extern void ddprintf(const char *fmt, ...); followed by void ddprintf(va_alist) va_dcl { ? The answer is in fact contained in the FAQ answers, but here it is again. EXCEPT IN RESTRICTED CIRCUMSTANCES, PROTOTYPE DECLARATIONS ARE NOT COMPATIBLE WITH OLD-STYLE DEFINITIONS. Note that both extern void ddprintf(const char *fmt, ...); and void ddprintf(const char *fmt, ...); are declarations. The word `extern' is ignored when declaring functions. The difference between a function declaration and a function definition is that a declaration ends with a balancing close parenthesis followed by a semicolon, while a definition ends with a balancing close parenthesis followed by an opening `{'. It is incorrect to put `extern' in front of a definition: `extern' is *not* ignored when DEFINING functions, only when DECLARING them. A prototype declaration tells the compiler: `This name is the name of a function. It has a fixed number of arguments, and each of these has a fixed type. The function returns a fixed type. Remember all of these facts.' If the declaration contains a `, ...' before the closing parenthesis, this changes to: `This name is the name of a function. It has a variable number of arguments, preceded by a fixed number of arguments. Each of the latter has a fixed type. The function returns a fixed type. Remember all of these facts.' When the compiler discovers a prototype DEFINITION, it treats that as another declaration (or the first declaration, if there have been no other declarations for the function) and makes sure the arguments match in number and types, and that the return type matches; it then compiles code for the function body. When the compiler discovers an old-style declaration or definition, however, this tells the compiler: `This name is the name of a function. It may or may not have some arguments. The arguments, if any, are not variable. The function returns a fixed type. Remember all of these facts.' The latter can sometimes, but by no means always, be reconciled with a prototype declaration that gave the same name and return type, but also gave the number and types of the arguments. It is not too difficult to define exactly when this can be done, although the result can be surprising. A: The arguments must be fixed, not variable. The ANSI standard permits compilers to use different calling sequences for fixed- and variable-argument functions, and therefore requires the programmer to announce variable-argument functions `in advance', as it were, using a prototype. All others are assumed to be fixed-arguments. B: None of the arguments in the prototype being reconciled against the definition may have a type which differs from its image under promotion. What B really means is that no argument can have type `char', `short', or `float' or any of their signed or unsigned variants. In other words, although int putc(int c, FILE *f); int putc(c, f) int c; FILE *f; { ... } /* ok */ is legal, the following is not: int put1(char c, FILE *f); int put1(c, f) char c; FILE *f; { ... } /* bad */ Since the image of `char' under promotion is `int', this fails rule B. Likewise, float mul(float, float); float mul(x, y) float x, y; { ... } /* bad */ is illegal, because the image of `float' under promotion is `double'. The reason for restriction B has to do with backwards compatibility (being able to run the mounds of code that use old-style definitions) without requiring systems to promote *all* arguments (being able to pass `float's around without turning them into `double's, etc). Any C system can *allow* the codes marked `bad' to work, but no C system is *required* to do so. So (after 162 lines), the answer is: declare your function as /* with optional `extern' included here */ extern void ddprintf(const char *fmt, ...); and define it as void ddprintf(const char *fmt, ...) { and any ANSI C system is obliged to compile it correctly. Do anything else and all bets are off. Since older C compilers do not recognize the `, ...' syntax, you may have to write: #ifdef HAVE_PROTOTYPE_DECLARATIONS void ddprintf(constchar *fmt, ...); #else void ddprintf(); #endif and #ifdef HAVE_PROTOTYPE_DEFINITIONS void ddprintf(const char *fmt, ...) { #else void ddprintf(va_alist) va_dcl { char *fmt; #endif va_alist ap; #ifdef HAVE_PROTYTYPE_DEFINITIONS va_start(ap, fmt); #else va_start(ap); fmt = va_arg(ap, char *); #endif ... -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 405 2750) Domain: chris@cs.umd.edu Path: uunet!mimsy!chris
darcy@druid.uucp (D'Arcy J.M. Cain) (11/06/90)
In article <3933.27353319@cc.helsinki.fi> jaakola@cc.helsinki.fi writes: >Why do *I* have to do the copying for all my functions, while there's >the compiler which a) is supposed to work for me and not vice versa > and b) should know ANSI peculiarities better than I do? > > static void auxiliary_func(a) /* private helper-function */ > int a; > { > ... > } > > void visible_fun(b) > int b; > { > ... > auxiliary_func(b+1); /* should be checked */ > ... > } > >The point is, why should I have to tell the compiler twice the type of >auxiliary_func? The prototype should be necessary only if I make a All ANSI compilers that I have used do exactly that. You do of course have to declare the function in an ANSI compliant way but once you do it is effectively prototyped from that point on. In the above example replace the first two lines with: static void auxiliary_func(int a) /* private helper-function */ The only time that I have to retype (or copy) a prototype is when the function is used in a different module. > >Another ANSI-misfeature is the ability to make declarations such as: > > int foo(int b, char *s) > >I like much more the old style > > int foo(b,s) > int b; /* the b means ... blahblahblah */ > char *s; /* the s means ... */ > >This is better, because you can have function name and args on the same >line, so that you can query all function names by grep-like tools (grep >outputs only single lines, which is very compact and - I think - >readable format). If you have much args, this way you can still put all >of them on a single line. So that just means we need smarter tools, not that we should stand still for fear of disturbing something. > >After the first line I tell the types of each arg and use comments after >each args as shown above. Where suitable I do the same thing: int foo( int b, /* the b means ... blahblahblah */ char *s) /* the s means ... */ -- D'Arcy J.M. Cain (darcy@druid) | D'Arcy Cain Consulting | I support gun control. West Hill, Ontario, Canada | Let's start with the government! + 416 281 6094 |
stanley@phoenix.com (John Stanley) (11/07/90)
rjc@uk.ac.ed.cstr (Richard Caley) writes: > In article <3933.27353319@cc.helsinki.fi> jaakola@cc.helsinki.fi writes: > > It's okay for me to make an include file, where I declare functions that > are visible to other modules. But consider the following example: > > static void auxiliary_func(a) /* private helper-function */ > int a; > { > The point is, why should I have to tell the compiler twice the type of > auxiliary_func? > > You don't. In the above case you havn't even told it once. If you > did... No, he most certainly DID tell the compiler the type of the function. This is one of those prior art things that the ANSI committee had to maintain. It is called a function definition (old style), and has scope of 'global to file'. He even told the compiler the type of arguement a. The compiler should most certainly know the type of the function when it sees it later within the other function. Because it is the old-style definition, the compiler is not required to keep track of the type of the parameter a required by that fucntion, so there will be no type checking on a. There most certainly should be type checking on the function itself. And the compiler should absolutely not generate an error on this syntax. > static void auxiliary_func(int a) > > { > > you wouldn't need to type anything more. Or if you did that would be a > massive compiler misfeature. This even saves you a couple of > characters :-) Moving the declaration of a into the parameter list converts this definition into new style. The only difference between old and new in this case is that the compiler is now required to type check the _parameter_ passed to a. Through other communication with Mr. Jaakola, it turns out that this is a misfeature of Microsoft C. <> "Aneth! That's a charming place!" "You've been to Aneth?" <> "Yes, but not yet." -- The Doctor and Seth, "The Horns of Nimon". >< <> "Sanity check!" "Sorry, we can't accept it, it's from out of state." - me
gwyn@smoke.brl.mil (Doug Gwyn) (11/07/90)
In article <3933.27353319@cc.helsinki.fi> jaakola@cc.helsinki.fi writes: >Why do *I* have to do the copying for all my functions, while there's >the compiler which a) is supposed to work for me and not vice versa > and b) should know ANSI peculiarities better than I do? Oh, for Christ's sake, nobody is forcing you to do anything. If you don't like prototypes just don't use them! >Another ANSI-misfeature is the ability to make declarations such as: > int foo(int b, char *s) >I like much more the old style > int foo(b,s) > int b; /* the b means ... blahblahblah */ > char *s; /* the s means ... */ And what prevents you from using the old style if you like it better? By the way, some people like to use the new style definitions like this: int foo( /* returns ... */ int b; /* the b means ... blahblahblah */ char *s; /* the s means ... */ ) >This is better, because you can have function name and args on the same >line, so that you can query all function names by grep-like tools But you have no idea what the argument types are that way; the new style is better in that respect. All that your posting really said is that you're comfortable doing things a particular way and do not wish to change. Nobody is making you change.
scs@adam.mit.edu (Steve Summit) (11/08/90)
In article <14382@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes: >Oh, for Christ's sake, nobody is forcing you to do anything. If you >don't like prototypes just don't use them! >...what prevents you from using the old style if you like it better? Section 3.9.5, which is a red flag to any responsible programmer; a standard which marks a feature as "obsolescent" is clearly stating that the feature may be withdrawn later, that it is being included only for the benefit of existing code, and that new code is well advised not to use it. (I'm sure Doug knows this.) Actually, I thought I might be editorializing a bit there, but the definition of obsolescent in section 1.8 says the same thing. I'm still using old-style definitions and declarations, but I expect to start taking flak for it soon, because the party line today seems to be that prototypes are a Good Thing. I don't particularly like them, mostly because of the maintenance issues several people have already mentioned. (At least now I know I'm not the only one who feels that way!) I'll probably convert to them myself, though, as soon as all the compilers I use support them, or whenever I start using tricks like the one Karl Heuer will remind us of next. I feel it's as likely that old-style function syntax will be removed in 10 years or so as it was that =+ and the like would be removed 10 years or so after they were officially deprecated. (Oh, look: they _were_ removed :-) .) Steve Summit scs@adam.mit.edu
brad@SSD.CSD.HARRIS.COM (Brad Appleton) (11/09/90)
I grabbed a PD prototype generator utility written in C (that I think works for both ANSI and K&R) not too long ago - its pretty small - here it is: I have a 10 line awk script that does it too but the C program is obviously a wee bit more portable ;-) Its only two files (a .c and a .h file). Actually its only one file - it can create its own .h file but you need to get it running first :-) Anyway - im sure some of you will find some use for it! Its written in K&R but Im sure it would be no problem to convert to ANSI. ______________________ "And miles to go before I sleep." ______________________ Brad Appleton brad@ssd.csd.harris.com Harris Computer Systems uunet!hcx1!brad Fort Lauderdale, FL USA ~~~~~~~~~~~~~~~~~~~~ Disclaimer: I said it, not my company! ~~~~~~~~~~~~~~~~~~~ ------------------------------ cut here --------------------------------------- # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by brad on Thu Nov 8 11:41:53 EST 1990 # Contents: mkproto.c mkproto.h echo x - mkproto.c sed 's/^@//' > "mkproto.c" <<'@//E*O*F mkproto.c//' /* Program to extract function declarations from C source code */ /* Written by Eric R. Smith and placed in the public domain */ /* Thanks are due to Jwahar R. Bammi for fixing several bugs */ /* and providing the Unix makefiles. S. Manoharan included a */ /* Getopt() function and modified the code to handle C++ style */ /* comments and member functions. */ #if defined(__STDC__) && !defined(minix) #include <stddef.h> #include <stdlib.h> #else #define EXIT_SUCCESS 0 #define EXIT_FAILURE 1 extern char *malloc(); #endif #include <stdio.h> #include <ctype.h> #include <string.h> #define DEBUG(s) { if (dodebug) fputs(s, stderr); } /* */ /*#define DEBUG(s) /* */ #define ISCSYM(x) ((x) > 0 && (isalnum(x) || (x) == '_')) #define ABORTED ( (Word *) -1 ) #define MAXPARAM 20 /* max. number of parameters to a function */ #define NEWBUFSIZ (20480*sizeof(char)) /* new buffer size */ typedef enum { false = 0, true = 1 } Boolean; Boolean newline_seen = true; /* are we at the start of a line */ Boolean dostatic = false; /* do static functions? */ Boolean donum = false; /* print line numbers? */ Boolean dopromote = true; /* promote certain sc-specifiers */ Boolean dohead = true; /* do file headers? */ Boolean dodebug = false; /* do debugging? */ Boolean docond = false; /* conditionalize for non-ANSI compilers */ long linenum = 1L; /* line number in current file */ int glastc = ' '; /* last char. seen by getsym() */ int inquote = 0; /* in a quote?? */ typedef struct word { struct word *next; char string[1]; } Word; #include "mkproto.h" /* * Routines for manipulating lists of words. */ Word *word_alloc(s) char *s; { Word *w; w = (Word *) malloc((unsigned)sizeof(Word) + strlen(s) + 1); /* ++jrb */ (void)strcpy(w->string, s); w->next = NULL; return w; } void word_free(w) Word *w; { Word *oldw; while (w) { oldw = w; w = w->next; free((char *)oldw); } } /* return the length of a list; empty words are not counted */ int List_len(w) Word *w; { int count = 0; while (w) { if (*w->string) count++; w = w->next; } return count; } /* Append two lists, and return the result */ Word *word_append(w1, w2) Word *w1, *w2; { Word *r, *w; r = w = word_alloc(""); while (w1) { w->next = word_alloc(w1->string); w = w->next; w1 = w1->next; } while (w2) { w->next = word_alloc(w2->string); w = w->next; w2 = w2->next; } return r; } /* see if the last entry in w2 is in w1 */ int foundin(w1, w2) Word *w1, *w2; { while (w2->next) w2 = w2->next; while (w1) { if (!strcmp(w1->string, w2->string)) return 1; w1 = w1->next; } return 0; } /* add the string s to the given list of words */ void addword(w, s) Word *w; char *s; { while (w->next) w = w->next; w->next = word_alloc(s); } /* given a list representing a type and a variable name, extract just * the base type, e.g. "struct word *x" would yield "struct word" */ Word *typelist(p) Word *p; { Word *w, *r; r = w = word_alloc(""); while (p && p->next) { if (p->string[0] && !ISCSYM(p->string[0])) break; w->next = word_alloc(p->string); w = w->next; p = p->next; } return r; } /* typefixhack: promote formal parameters of type "char", * "unsigned char", "short", or "unsigned short" to "int". */ void typefixhack(w) Word *w; { Word *oldw = 0; while (w) { if (*w->string) { if ( (!strcmp(w->string, "char") || !strcmp(w->string, "short") ) && (List_len(w->next) < 2) ) { if (oldw && !strcmp(oldw->string, "unsigned")) { oldw->next = w->next; free((char *)w); w = oldw; } (void)strcpy(w->string, "int"); } } w = w->next; } } /* read a character: if it's a newline, increment the line count */ int ngetc(f) FILE *f; { int c; c = getc(f); if (c == '\n') linenum++; return c; } /* read the next character from the file. If the character is '\' then * read and skip the next character. Any comment sequence is converted * to a blank. [ Both C and C++ style comments are considered - sam ] */ int fnextch(f) FILE *f; { int c, lastc, incomment; c = ngetc(f); while (c == '\\') { DEBUG("fnextch: in backslash loop\n"); c = ngetc(f); /* skip a character */ c = ngetc(f); } if (c == '/' && !inquote) { c = ngetc(f); if (c == '*') { /* C comments */ incomment = 1; c = ' '; DEBUG("fnextch: comment seen\n"); while (incomment) { lastc = c; c = ngetc(f); if (lastc == '*' && c == '/') incomment = 0; else if (c < 0) return c; } return fnextch(f); } else if ( c == '/' ) { /* C++ comments */ incomment = 1; c = ' '; DEBUG("fnextch: C++ comment seen\n"); while ( c != '\n' ) { c = ngetc(f); } incomment = 0; return fnextch(f); } else { if (c == '\n') linenum--; (void)ungetc(c, f); return '/'; } } return c; } /* Get the next "interesting" character. Comments are skipped, and * strings are converted to "0". Also, if a line starts with "#" * it is skipped. */ int nextch(f) FILE *f; { int c; c = fnextch(f); if (newline_seen && c == '#') { do { c = fnextch(f); } while (c >= 0 && c != '\n'); if (c < 0) return c; } newline_seen = (c == '\n') ? true : false; if (c == '\'' || c == '\"') { DEBUG("nextch: in a quote\n"); inquote = c; while ( (c = fnextch(f)) >= 0 ) { if (c == inquote) { inquote = 0; DEBUG("nextch: out of quote\n"); return '0'; } } DEBUG("nextch: EOF in a quote\n"); } return c; } /* * Get the next symbol from the file, skipping blanks. * Return 0 if OK, -1 for EOF. * Also collapses everything between { and } */ int getsym(buf, f) char *buf; FILE *f; { register int c; int inbrack = 0; DEBUG("in getsym\n"); c = glastc; while ((c > 0) && isspace(c)) { c = nextch(f); } DEBUG("getsym: spaces skipped\n"); if (c < 0) { DEBUG("EOF read in getsym\n"); return -1; } if (c == '{') { inbrack = 1; DEBUG("getsym: in bracket\n"); while (inbrack) { c = nextch(f); if (c < 0) { DEBUG("getsym: EOF seen in bracket loop\n"); glastc = c; return c; } if (c == '{') inbrack++; else if (c == '}') inbrack--; } (void)strcpy(buf, "{}"); glastc = nextch(f); DEBUG("getsym: out of in bracket loop\n"); return 0; } if (!ISCSYM(c)) { *buf++ = c; *buf = 0; glastc = nextch(f); DEBUG("getsym: returning special symbol\n"); return 0; } while (ISCSYM(c)) { *buf++ = c; c = nextch(f); } *buf = 0; glastc = c; DEBUG("getsym: returning word\n"); return 0; } /* * skipit: skip until a ";" or the end of a function declaration is seen */ int skipit(buf, f) char *buf; FILE *f; { int i; do { DEBUG("in skipit loop\n"); i = getsym(buf, f); if (i < 0) return i; } while (*buf != ';' && *buf != '{'); return 0; } /* * Get a parameter list; when this is called the next symbol in line * should be the first thing in the list. */ Word *getparamlist(f) FILE *f; { static Word *pname[MAXPARAM]; /* parameter names */ Word *tlist, /* type name */ *plist; /* temporary */ int np = 0; /* number of parameters */ int typed[MAXPARAM]; /* parameter has been given a type */ int tlistdone; /* finished finding the type name */ int sawsomething; int i; int inparen = 0; char buf[80]; DEBUG("in getparamlist\n"); for (i = 0; i < MAXPARAM; i++) typed[i] = 0; plist = word_alloc(""); /* first, get the stuff inside brackets (if anything) */ sawsomething = 0; /* gets set nonzero when we see an arg */ for (;;) { if (getsym(buf, f) < 0) return NULL; if (*buf == ')' && (--inparen < 0)) { if (sawsomething) { /* if we've seen an arg */ pname[np] = plist; plist = word_alloc(""); np++; } break; } if (*buf == ';') { /* something weird */ return ABORTED; } sawsomething = 1; /* there's something in the arg. list */ if (*buf == ',' && inparen == 0) { pname[np] = plist; plist = word_alloc(""); np++; } else { addword(plist, buf); if (*buf == '(') inparen++; } } /* next, get the declarations after the function header */ inparen = 0; tlist = word_alloc(""); plist = word_alloc(""); tlistdone = 0; sawsomething = 0; for(;;) { if (getsym(buf, f) < 0) return NULL; /* handle a list like "int x,y,z" */ if (*buf == ',' && !inparen) { if (!sawsomething) return NULL; for (i = 0; i < np; i++) { if (!typed[i] && foundin(plist, pname[i])) { typed[i] = 1; word_free(pname[i]); pname[i] = word_append(tlist, plist); /* promote types */ if ( dopromote ) typefixhack(pname[i]); break; } } if (!tlistdone) { tlist = typelist(plist); tlistdone = 1; } word_free(plist); plist = word_alloc(""); } /* handle the end of a list */ else if (*buf == ';') { if (!sawsomething) return ABORTED; for (i = 0; i < np; i++) { if (!typed[i] && foundin(plist, pname[i])) { typed[i] = 1; word_free(pname[i]); pname[i] = word_append(tlist, plist); /* promote types */ if ( dopromote ) typefixhack(pname[i]); break; } } tlistdone = 0; word_free(tlist); word_free(plist); tlist = word_alloc(""); plist = word_alloc(""); } /* handle the beginning of the function */ else if (!strcmp(buf, "{}")) break; /* otherwise, throw the word into the list (except for "register") */ else if (strcmp(buf, "register")) { sawsomething = 1; addword(plist, buf); if (*buf == '(') inparen++; if (*buf == ')') inparen--; } } /* Now take the info we have and build a prototype list */ /* empty parameter list means "void" */ if (np == 0) return word_alloc("void"); plist = tlist = word_alloc(""); for (i = 0; i < np; i++) { /* If no type provided, make it an "int" */ if ( !(pname[i]->next) || (!(pname[i]->next->next)&&strcmp(pname[i]->next->string, "void"))) { addword(tlist, "int"); } while (tlist->next) tlist = tlist->next; tlist->next = pname[i]; if (i < np - 1) addword(tlist, ", "); } return plist; } /* * emit a function declaration. The attributes and name of the function * are in wlist; the parameters are in plist. */ void emit(wlist, plist, startline) Word *wlist, *plist; long startline; { Word *w; int count = 0; DEBUG("emit called\n"); if (donum) (void)printf("/*%8ld */ ", startline); for (w = wlist; w; w = w->next) { if ( w->string[0] == ':' ) return; /* C++ member function detected */ if (w->string[0]) count ++; } if (count < 2) (void)printf("int "); for (w = wlist; w; w = w->next) { (void)printf("%s", w->string); if (ISCSYM(w->string[0])) (void)printf(" "); } if (docond) (void)printf("PROTO(("); else (void)printf("( "); for (w = plist; w; w = w->next) { (void)printf("%s", w->string); if (ISCSYM(w->string[0])) (void)printf(" "); } if (docond) (void)printf("));\n"); else (void)printf(");\n"); } /* * get all the function declarations */ void getdecl(f) FILE *f; { Word *plist, *wlist = NULL; char buf[80]; int sawsomething; long startline; /* line where declaration started */ int oktoprint; again: word_free(wlist); wlist = word_alloc(""); sawsomething = 0; oktoprint = 1; for(;;) { DEBUG("main getdecl loop\n"); if (getsym(buf,f) < 0) { DEBUG("EOF in getdecl loop\n"); return; } /* try to guess when a declaration is not an external function definition */ if (!strcmp(buf, ",") || !strcmp(buf, "{}") || !strcmp(buf, "=") || !strcmp(buf, "typedef") || !strcmp(buf, "extern")) { (void)skipit(buf, f); goto again; } if (!dostatic && !strcmp(buf, "static")) { oktoprint = 0; } /* for the benefit of compilers that allow "inline" declarations */ if (!strcmp(buf, "inline") && !sawsomething) continue; if (!strcmp(buf, ";")) goto again; /* A left parenthesis *might* indicate a function definition */ if (!strcmp(buf, "(")) { startline = linenum; if (!sawsomething || !(plist = getparamlist(f))) { (void)skipit(buf, f); goto again; } if (plist == ABORTED) goto again; /* It seems to have been what we wanted */ if (oktoprint) emit(wlist, plist, startline); word_free(plist); goto again; } addword(wlist, buf); sawsomething = 1; } } void main(argc, argv) int argc; char *argv[]; { FILE *f; char *iobuf; char *title = "UNSPECIFIEDHEADERTITLE"; extern void Usage(); int opch; extern int Optind; extern char *Optarg; while ( ( opch = Getopt(argc,argv,"h:snpPD") ) != -1 ) switch ( opch ) { case 'h' : (void)strcpy(title, Optarg); break; case 's' : dostatic = true; break; case 'n' : donum = true; break; case 'p' : docond = true; break; case 'P' : dopromote = false; break; case 'D' : dodebug = true; break; default : Usage(argv[0]); exit(0); } /* ensw */ iobuf = malloc((unsigned)NEWBUFSIZ); (void)printf("#ifndef %s\n", title); (void)printf("#define %s\n", title); if (docond) { (void)printf("#ifdef __STDC__\n"); (void)printf("# define\tPROTO(s) s\n"); (void)printf("#else\n"); (void)printf("# define PROTO(s) ()\n"); (void)printf("#endif\n\n"); } if ( Optind > argc ) getdecl(stdin); else for ( ; Optind < argc; ++Optind ) { DEBUG("trying a new file\n"); if ( ( f = fopen(argv[Optind],"r") ) == (FILE *)0 ) { (void)fprintf(stderr,"%s: cannot open %s\n", argv[0], argv[Optind]); continue; } /* do the file operations here */ /* if (iobuf) (void)setvbuf(f, iobuf, _IOFBF, NEWBUFSIZ); /* */ if (dohead) (void)printf("\n/* %s */\n", argv[Optind]); linenum = 1; newline_seen = true; glastc = ' '; DEBUG("calling getdecl\n"); getdecl(f); DEBUG("back from getdecl\n"); DEBUG("back from fclose\n"); (void)fclose(f); } /* enfo */ if (docond) { (void)printf("\n#undef PROTO\n"); /* clean up namespace */ } (void)printf("\n#endif\n"); exit(EXIT_SUCCESS); } void Usage(progname) char *progname; { (void)fprintf(stderr,"Usage: %s [options][files ...]\n",progname); (void)fprintf(stderr, "\t-n: put line numbers of declarations as comments\n"); (void)fprintf(stderr, "\t-s: include declarations for static functions\n"); (void)fprintf(stderr, "\t-p: make header files readable by non-ANSI compilers\n"); (void)fprintf(stderr, "\t-P: don't promote any sc-specifiers\n"); (void)fprintf(stderr, "\t-h HeaderTitle: use HeaderTitle to title the header file\n"); (void)fprintf(stderr, "\t-D: operate on debug mode\n"); exit(EXIT_FAILURE); } #ifndef lint static char *scid = "s. manoharan edinburgh univ"; #endif #include<stdio.h> char *Optarg; int Optind; int Getopt(argc,argv,options) int argc; char **argv; char *options; { char *str, *ptr; char opch; char *Strchr(); static int flag = 0; static int Argc; static char **Argv; if ( flag == 0 ) { Argc = argc; Argv = argv; flag = 1; Optind = 1; } if ( Argc <= 1 ) return -1; if ( --Argc >= 1 ) { str = *++Argv; if (*str != '-') return -1; /* argument is not an option */ else { /* argument is an option */ if ( ( ptr = Strchr(options, opch = *++str) ) != (char *) 0 ) { ++Optind; Optarg = ++str; /* point to rest of argument if any */ if ( ( *++ptr == ':' ) && ( *Optarg == '\0' ) ) { if (--Argc <= 0) return '?'; Optarg = *++Argv; ++Optind; } return opch; } else if ( opch == '-' ) { /* end of options */ ++Optind; return -1; } else return '?'; } } return 0; /* this will never be reached */ } /* EnGetopt */ char *Strchr(s,c) char *s; char c; { while ( *s != '\0' ) { if ( *s == c ) return s; else ++s; } return ( (char *) 0 ); } /* EnStrchr */ @//E*O*F mkproto.c// chmod u=rw,g=,o= mkproto.c echo x - mkproto.h sed 's/^@//' > "mkproto.h" <<'@//E*O*F mkproto.h//' #ifdef __STDC__ # define PROTO(s) s #else # define PROTO(s) () #endif /* mkproto.c */ Word *word_alloc PROTO((char *s )); void word_free PROTO((Word *w )); int List_len PROTO((Word *w )); Word *word_append PROTO((Word *w1 , Word *w2 )); int foundin PROTO((Word *w1 , Word *w2 )); void addword PROTO((Word *w , char *s )); Word *typelist PROTO((Word *p )); void typefixhack PROTO((Word *w )); int ngetc PROTO((FILE *f )); int fnextch PROTO((FILE *f )); int nextch PROTO((FILE *f )); int getsym PROTO((char *buf , FILE *f )); int skipit PROTO((char *buf , FILE *f )); Word *getparamlist PROTO((FILE *f )); void emit PROTO((Word *wlist , Word *plist , long startline )); void getdecl PROTO((FILE *f )); void main PROTO((int argc , char **argv )); void Usage PROTO((void )); #undef PROTO @//E*O*F mkproto.h// chmod u=rw,g=,o= mkproto.h exit 0 ______________________ "And miles to go before I sleep." ______________________ Brad Appleton brad@ssd.csd.harris.com Harris Computer Systems uunet!hcx1!brad Fort Lauderdale, FL USA ~~~~~~~~~~~~~~~~~~~~ Disclaimer: I said it, not my company! ~~~~~~~~~~~~~~~~~~~
bright@nazgul.UUCP (Walter Bright) (11/09/90)
In article <3933.27353319@cc.helsinki.fi> jaakola@cc.helsinki.fi writes:
/ static void auxiliary_func(a) /* private helper-function */
/ int a;
/ {
/ }
/ void visible_fun(b)
/ int b;
/ {
/ ...
/ auxiliary_func(b+1); /* should be checked */
/ ...
/ }
/
/The point is, why should I have to tell the compiler twice the type of
/auxiliary_func? The prototype should be necessary only if I make a
/forward reference to make it easier for the compiler to check types in a
/single pass. I think the function definition tells unambiguously the
/types, so I should not have to watch warnings such as "function
/definition used as a prototype" (Microsoft C 5.1).
In Zortech, the first function declaration does result in a prototype
being declared (internal to the compiler) and all future uses of
auxiliary_func are checked against that prototype.
In fact, the first use of a function, in the absence of a prototype,
causes a prototype to be generated for that function based on the
default argument promotion rules. This is not ANSI behavior, and can
be disabled with the -P switch, but is very useful in checking for
errors in old K&R code.
The -r switch, strict prototyping, is also available, which enforces a
rule that all uses of a function must have a prototype in scope for it.
I use this switch for all my code, and recommend its use, as it results
in the bugs being caught at the earliest possible time (when they are
the cheapest to fix!).
stever@Octopus.COM (Steve Resnick ) (11/11/90)
In article <151@nazgul.UUCP> bright@nazgul.UUCP (Walter Bright) writes: [Stuff Deleted] >/The point is, why should I have to tell the compiler twice the type of >/auxiliary_func? The prototype should be necessary only if I make a >/forward reference to make it easier for the compiler to check types in a >/single pass. I think the function definition tells unambiguously the >/types, so I should not have to watch warnings such as "function >/definition used as a prototype" (Microsoft C 5.1). > >In Zortech, the first function declaration does result in a prototype >being declared (internal to the compiler) and all future uses of >auxiliary_func are checked against that prototype. > >In fact, the first use of a function, in the absence of a prototype, >causes a prototype to be generated for that function based on the >default argument promotion rules. This is not ANSI behavior, and can >be disabled with the -P switch, but is very useful in checking for >errors in old K&R code. > >The -r switch, strict prototyping, is also available, which enforces a >rule that all uses of a function must have a prototype in scope for it. >I use this switch for all my code, and recommend its use, as it results >in the bugs being caught at the earliest possible time (when they are >the cheapest to fix!). Both C compilers I use (Turbo C on DOS and Microsoft C on OS/2) do the same thing. (At least from my perspective). Turbo C doesn't generate warnings or anything at all, but takes a function definition as a prototype (it WILL warn about mis-matched types in parameters in calls to functions with previous definitions but no prototype.) Microsoft C generates a warning. foo.c(6) : warning C4103: 'main' : function definition used as prototype The warning is generated, however, at the first call to the function versus the function definition. I guess the would be correct behaviour. Just as a matter of course, however, I usually use prototypes on all functions, since this helps with conflicts on the PC in regards to pointer sizes, etc and it helps document the code, too. Adding my $.02 (unless it has devaluated already) Steve -- ---------------------------------------------------------------------------- steve.resnick@f105.n143.z1.FIDONET.ORG - or - apple!camphq!105!steve.resnick Flames, grammar errors, spelling errrors >/dev/nul The Asylum OS/2 BBS - (408)263-8017 IFNA 1:143/105.0
utility@quiche.cs.mcgill.ca (Ronald BODKIN) (11/24/90)
In article <1906@necisa.ho.necisa.oz> boyd@necisa.ho.necisa.oz (Boyd Roberts) writes: >Right on! The function prototypes are just stupid. I shouldn't have to go: > extern gore *good(const char *vomit); >to get the functionality of type checking of function arguments. >The compiler and loader should do it. However, one prototype will allow you to automatically coerce things like ints to longs/floats/doubles or "near" pointers to "far" pointers, etc. Also, it is much faster to catch a prototype problem before linking a large application. Ron
jrv@sdimax2.mitre.org (VanZandt) (11/28/90)
In article <75@homer.cs.mcgill.ca> utility@quiche.cs.mcgill.ca (Ronald BODKIN) writes: >In article <1906@necisa.ho.necisa.oz> boyd@necisa.ho.necisa.oz (Boyd Roberts) writes: >>Right on! The function prototypes are just stupid. I shouldn't have to go: > >> extern gore *good(const char *vomit); Speaking of which, qsort() requires a comparison routine declared as int sort_function( const void *a , const void *b ) Is there a convenient way to write such functions without using a cast for every reference to a or b? Copying their values into local pointers of the appropriate type seems a kludge. I suppose I could avoid #including stdlib.h, and declare the arguments to be whatever type I liked. - Jim Van Zandt
gwyn@smoke.brl.mil (Doug Gwyn) (11/29/90)
In article <126872@linus.mitre.org> jrv@sdimax2.mitre.org (VanZandt) writes: >Is there a convenient way to write such functions without using a cast for >every reference to a or b? Copying their values into local pointers of the >appropriate type seems a kludge. I suppose I could avoid #including stdlib.h, >and declare the arguments to be whatever type I liked. If you don't declare the argument types properly, your code will not be strictly conforming. The only "cheat" that is allowed is to use char* instead of void*, because the standard required these to have the same representation. This is NOT required for other pointer types, just for these two. The three obvious solutions are: explicit cast on each usage of the arguments use a macro to encapsulate the above casting use auto variables of the appropriate type
dswartz@bigbootay.sw.stratus.com (01/15/91)
Here's my problem: I have a program with a couple of procedures which use the varargs package (for tracing and debugging.) I have an include file which defines prototypes for all of the procedures in the source file. The problem is that to make the calling references happy, I seem to need to use the syntax "void foobar (char *, ...);" Unfortunately, the varargs.h on my system defines the dummy argument as an int and there is only one such argument, so this disagrees with the prototype. I have gotten around this by placing all of the varargs routines in a separate file which doesn't include the prototype include file. Am I out to lunch, or is there an "official" way to do this? -- Dan S.