russ@motto.UUCP (Russell Crook) (09/14/88)
(line eater fodder) (Posted for a development group here that doesn't have direct net access. Please mail replies to russ@motto). We are just starting to use function prototypes, and are looking for suggestions on how to use them. We know that the Microsoft C compiler can automatically generate function prototypes. Where do you go from there? When developing a large program, composed of many source files, how do you make sure each file picks up the right prototypes for the functions it uses? Are there conventions about where prototypes are stored - do you put them in '.h' files, or right in the source file, or somewhere else? Do you put all the prototypes for an entire program in one file, or do you use some means of only picking up the ones which are needed? If you put them all in, does it affect compile time significantly? Do you regenerate the prototypes automatically, every time you rebuild or whenever the source file changes, or what? We also do cross-development under VMS - does anyone have a portable program to generate function prototypes? -- Russell Crook (UUCP: ...!uunet!mnetor!motto!russ) Disclaimer: "...we're all mad here. I'm mad. You're mad." "How do you know I'm mad?" said Alice. "You must be", said the Cat, "or you wouldn't have come here."
gwyn@smoke.ARPA (Doug Gwyn ) (09/16/88)
In article <24@motto.UUCP> russ@motto.UUCP (Russell Crook) writes: >Are there conventions about where prototypes are stored - >do you put them in '.h' files, or right in the source file, or >somewhere else? Prototypes don't change the recommended C practice, namely use header files to define/declare all interface information. The best approach is to use separate headers (and separate source files) for each group of functionally related capabilities. For example, "parse.h" would declare the parsing function(s) that are of use to other parts of the application, and it would also define any manifest constants, data types, etc. that are specific to parsing. Other headers would cover other functional areas. And of course, a Makefile or equivalent compilation specification could be used to limit recompilation to just the affected sources when a change has been made.
swarbric@tramp.Colorado.EDU (Frank Swarbrick) (09/17/88)
In article <24@motto.UUCP> russ@motto.UUCP (Russell Crook) writes: >We are just starting to use function prototypes, and are looking for >suggestions on how to use them. > >We know that the Microsoft C compiler can automatically generate >function prototypes. Where do you go from there? When developing >a large program, composed of many source files, how do you >make sure each file picks up the right prototypes for the functions >it uses? Are there conventions about where prototypes are stored - >do you put them in '.h' files, or right in the source file, or >somewhere else? Do you put all the prototypes for an entire program >in one file, or do you use some means of only picking up the ones >which are needed? If you put them all in, does it affect compile >time significantly? Well, I've only been using C for a little over a year, so I've always had a compiler that uses prototypes. This is probably why it's so hard for me to understand why people find them so hard to use. ANYWAY... I put all of the prototypes for non-static functions in a separate header file and then include it. For all the static (local to the file) functions I write them in the file itself. Here is an example. ------------------------- /* myfile.h */ void lalaland(void); void zzz(void); ------------------- /* myfile.c */ #include "myfile.h" static void foofoo(void); void main() { lalaland(); zzz(); } void lalaland() { /* stuff */ } void zzz() { /* more stuff */ } static void foofoo() { /* local stuff */ } >Do you regenerate the prototypes automatically, every time you rebuild >or whenever the source file changes, or what? I'm not quite sure what you mean. The header files are compiled every time they are #included, yes. It may waste a few seconds, depending on how large the header file(s) is(are). Frank Swarbrick (and, yes, the net.cat) | "1001001 -- S.O.S. University of Colorado, Boulder | 1001001 -- in distress swarbric@tramp.Colorado.EDU | 100100" :...!{ncar|nbires}!boulder!tramp!swarbric | -Rush
dalegass@dalcsug.UUCP (Dale Gass) (09/18/88)
My personal preference when using prototypes, is to put all the prototypes into one header file (proto.h, or whatever), which is included by all modules in the project; however, I don't declare the dependency of all the source files upon proto.h. This avoids having to recompile *all* the modules whenever you simply add the prototype of a new function to proto.h. It could prove dangerous if you *change* the syntax of the prototype in proto.h carelessly; whenver you change a syntax in proto.h, you should 'touch *.c' to remake all modules. But I find in development, the ability to quickly add to proto.h without having to recompile everything is a major time-saver. For maintenance work on a large project, I would probably declare the make dependency of the source files on proto.h, since modification of proto.h (when you change the syntax of a prototyped function) could be dangerous to existing modules (which won't be recompiled). Howeven, when one changes the syntax of a function, he should go through all his souces modules and change all the references to it, anyway (in which case, those modules will be recompiled and prototype-checked against proto.h)... -------------- -dalegass@dalcsug {watmath|uunet}!dalcs!dalcsug!dalegass
dwp@k.gp.cs.cmu.edu (Doug Philips) (09/19/88)
LineEaterHappiness++ I've used the following method on a medium sized project that run on PC clones under microsoft windows. The development environment started out as plain DOS (3.1) using MicroSoft C version 4.0. About 3 months into the project we switched to using the Mortice Kern systems package (ksh, diff, awk, sed, etc.). The microsoft compiler's ability to generate prototypes was the only mechanism used to generate prototypes. The underlying assumption was that the more that could be done automaticlly, the more it would be correct. For each source file F.c, there is a corresponding "internal interface" file F.i, which is the prototype output of the compiler having been run on F.c. This file is included only by F.c. Since the compiler was good enough to augment the prototypes with comments that indicate "global" functions, a simple script was used to extract the global routine prototypes into a file called "global.rtn", which was included by all source files. The rationale here is that since C would allow the function to be called anyway, it was best to make sure the prototypes were available. This meant adding new functions to a modules "external interface" was as easy as adding the routine and using it. Since it was too agonizingly slow to always compute these files, the makefile was doctored to break the dependency between F.c and F.i. Everytime I knew I made an interface change I would remove the F.i file. The rule for generating "global.rtn" would run a script. The script would generate a potential new file, but install it only if it was a change from the old version. About once a day, sometimes twice, I would remove all the generated files (.i, .o, etc) and let the world rebuild just to make sure. A good time to go get a coke, or whatever. Since then I've read a book called "Portable C and Unix System Programming" which had ideas similar to this. I don't remember the author (it's not in front of me now), but I THINK it was "Lapin". -Doug Philips ARPA: Doug.Philips@k.cs.cmu.edu -- Doug Philips "All that is gold does not glitter, Carnegie-Mellon University Not all those who wander are lost..." dwp@cs.cmu.edu -J.R.R. Tolkien
ray@micomvax.UUCP (Ray Dunn) (09/20/88)
In article <24@motto.UUCP> russ@motto.UUCP (Russell Crook) writes: >We are just starting to use function prototypes, and are looking for >suggestions on how to use them. >.... >Do you regenerate the prototypes automatically, every time you rebuild >or whenever the source file changes, or what? As others have said in various ways to the first part of the question - use function prototypes in the same way other global data is handled - include them in *appropriate* .h files - do *not* just use one big .h file for everything. Get into the habit of creating a prototype in an appropriate header file when you create a global function, in the same way you currently create any other extern statement. This .h file should be included in the "parent" source file, as well as in referencing files. If the procedure is static, put the prototype somewhere at the top of the source file. The answer to the automatic *generation* question is simple - do it once if your code has not used prototypes before (this is why MS provided the feature), disseminate the output into header files, then maintain the information manually as you would for any other global information. Continually re-generating prototypes can only lead to trouble, does not adequately separate "static" and "extern" declarations, and doesn't automatically get the information into the correct places. Define things as global only on a "Need to know" basis - i.e. put static in front of everything in sight! (:-)/2 Hopefully prototyping will increase the diligence of using that little word "static" when defining procedures which do not *need* to be global (desperately trying to avoid flaming the inappropriate overloading of the keyword "static" and the fact that the static/extern default is reversed from what it should be - something not worth arguing about because it is cast in 'C'oncrete)! -- Ray Dunn. | UUCP: ..!philabs!micomvax!ray Philips Electronics Ltd. | TEL : (514) 744-8200 Ext: 2347 600 Dr Frederik Philips Blvd | FAX : (514) 744-6455 St Laurent. Quebec. H4M 2S9 | TLX : 05-824090
peter@thirdi.UUCP (Peter Rowell) (09/23/88)
In article <1281@micomvax.UUCP> ray@micomvax.UUCP (Ray Dunn) writes: >In article <24@motto.UUCP> russ@motto.UUCP (Russell Crook) writes: >>We are just starting to use function prototypes, and are looking for >>suggestions on how to use them. >>.... >>Do you regenerate the prototypes automatically, every time you rebuild >>or whenever the source file changes, or what? > > ... > >The answer to the automatic *generation* question is simple - do it once if >your code has not used prototypes before (this is why MS provided the >feature), disseminate the output into header files, then maintain the >information manually as you would for any other global information. ^^^^^^^^ My experience shows that manual maintenance of this type of information, if done incorrectly, can lead to bugs that are incredibly difficult to find - particularly when the parameter types are used for doing automatic coercion, as specified for ANSI C. Our solution is (and has been for many years) to completely automate the generation of prototypes and general external information. Some languages/environments may support some or all of this process, but we have found portability requires we "roll our own". Using two new "keywords" (export and exportdefine) and a variety of shell and sed scripts, we regularly "re-edit" .h files so that they contain the latest definitions of constants, macro routines, global variables, functions and type information. Appropriate dependencies are maintained via our version of "make depend" - both for when the .h's need to be rebuilt and for when .c's need to be recompiled. During intense development cycles there can be quite a bit of unnecessary reebuilds/recompiles, so we kill the dependencies and depend on programmer knowledge of probable side effects. Every once in a while this fails and you get a weird bug, but then we do a "forced" rebuild of the universe and that normally fixes everything. Code shipped to customers always has full dependency information. We have discussed building a more knowledgable dependency system where .c files would be made explicitly dependent on each (implicitly or explicitly) imported value/variable/procedure/type. Although I know we will do this eventually, we are trying to get alpha 1.2 out the door, and we just don't have the time (I'm sure everyone else has oodles of time for stuff like this :-). Anyone wishing the actual sed/shell/.h files can email me at ...!pyramid!thirdi!peter. ---------------------------------------------------------------------- Peter Rowell "Gee, Dr. Science, can we depend on that prototype?" Third Eye Software, Inc. (415) 321-0967 Menlo Park, CA 94025 ...!pyramid!thirdi!peter
karl@haddock.ima.isc.com (Karl Heuer) (09/24/88)
In article <432@thirdi.UUCP> peter@thirdi.UUCP (Peter Rowell) writes: >In article <1281@micomvax.UUCP> ray@micomvax.UUCP (Ray Dunn) writes: >>[Generate the prototypes automatically the first time,] then maintain the >>information manually as you would for any other global information. > ^^^^^^^^ >My experience shows that manual maintenance of this type of information, >if done incorrectly, can lead to [hard-to-find bugs]. The compiler should catch them, if the header which contains the prototype is also included in the module that defines the function itself. >Our solution ... During intense development cycles there can be quite a bit >of unnecessary reebuilds/recompiles, so we kill the dependencies and depend >on programmer knowledge of probable side effects. My experience shows that manual maintenance of this type of information, if done incorrectly, can lead to hard-to-find bugs. :-) Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint