Path: utzoo!utgpu!news-server.csri.toronto.edu!torsqnt!lethe!druid!darcy From: darcy@druid.uucp (D'Arcy J.M. Cain) Newsgroups: comp.lang.c Subject: Re: lint (was: Funny mistake) Message-ID: <1991Mar24.165719.26908@druid.uucp> Date: 24 Mar 91 16:57:19 GMT References: <5036@goanna.cs.rmit.oz.au> <13627@helios.TAMU.EDU> <1991Mar23.043408.5260@athena.mit.edu> Organization: D'Arcy Cain Consulting, West Hill, Ontario Lines: 146 In article <1991Mar23.043408.5260@athena.mit.edu> scs@adam.mit.edu writes: >In article <13627@helios.TAMU.EDU> byron@archone.tamu.edu (Byron Rakitzis) writes: >I don't believe that ANSI C prototypes, as currently defined and >commonly implemented, are a sufficient solution to the problem of >cross-file declaration mismatches. As with anything the tool by itself is never a sufficient solution. Lint and prototypes both require intelligent use to get the most from them. I believe that prototypes used properly can enhance the development process. There is a commercial for Pert shampoo (is there such a thing as realpoo?) that shows a woman holding a bottle and easily moving around a locker room while someone in the background who supposedly is using the old style two bottle system that can barely stumble to the shower she is so overloaded with bottles, towels, etc. Somehow that one extra bottle of conditioner translates into an armful of stuff. Your post reminds me of that somewhat. Sure there is some more work required to work with prototypes but it isn't nearly so bad as you make it seem and I think the benefits really make it worhwhile in the long run. I have been using full prototypes for years and it has saved my bacon too many times to even consider going to some other system. First of all, the standard headers will take care of most of your checking. If you use a standard I/O function, #include stdio.h. If you are using any time functions then #include time.h. If you turn on enough warnings the compiler will remind you if you forget a header by pointing out that a function hasn't been prototyped. If you have a number of functions that are shared in a project, create a header file or a few headers where the functions are declared. Make sure to include the header in the file that defines the function. This is a check on the header file as well as the function. The header file can perform double duty if you wish by documenting the project as well as specifying the interfaces to the various routines. I have one header file that runs to ~16 pages with ~90% devoted to comments. It is in effect the functional specification for the sub-system it describes. Now if a change is made to the specification the sub-system as well as those programs that use it are automatically checked. As for the header file, consider the following: /* The foo function performs a framitz function on the string that */ /* is sent as the first argument and returns a pointer to a YABBA */ /* type */ YABBA *foo(char *s); Now we change the specification to this: /* The foo function performs a framitz function on the string that */ /* is sent as the first argument using the second argument sent as */ /* a filbert factor and returns a pointer to a YABBA type */ YABBA *foo(char *s); Note that we forgot to change the prototype. Assuming that we correct the actual function definition we will immediately see a problem when we do the compile and the header file, which is self-documenting, is easily fixed before we re-compile the functions that use the sub-system. >Prototypes catch almost as many errors as lint would (they don't >check data declarations), but they can also gloss over other >potential errors (by quietly inserting casts to the correct type), Exactly. I can do the following: #include ... int index; ... fseek(fp, index, SEEK_SET); and not have to worry about the conversion. Are you saying that it is better for the programmer to cast noisily rather than have the compiler do it quietly? >and they do their work only when the programmer has gone to the >considerable extra work of supplying the prototypes and keeping >them up-to-date. And I argue that the programmer should be making these design specifications before coding. Sure they may have to be modified as the project goes on but that isn't nearly as difficult as you make it seem. >aid of prototypes is essentially a two-pass affair: first you >have to chase down all the "function called with no prototype in >scope" warnings, and supply the missing prototypes so that a >second pass can use them to check your calls. How would you like >it if you had to give a spellchecking program a list of the >correctly-spelled words in the document to be checked?) But you do have to do this. Of course your vendor gives you a list to start with but you have to add your own from time to time because the list can never be complete. If you mean the list has to be in the actual document, of course that is the wrong place for them. Just as prototypes don't belong in the .c files. They belong in a file that can be included by the module defining the function as well as the one(s) using it. Of course you say essentially the same thing a few paragraphs later so I'm not sure what the above statemet is meant to suggest. >The use of prototypes can also dramatically increase >recompilation during development, because prototypes *must* be >placed in header files (see below), so you need lots of header >files (up to one per C source file), and they must be much more >widely #included. (It's true that in a carefully planned and My experience suggests that the ratio of header files to source files is much lower. Usually a project can be broken up into broadly defined subsections, each with it's own header/specification file. >properly managed project, changes or additions to module >interfaces, and therefore changes to prototypes and header files, >should be infrequent. On the other hand, incremental design and >implementation is not without its merits, and new interfaces can >be added all the time.) And let's not forget clients who change their minds every other day. A properly managed project, even with prototypes and header files, should be able to handle this. > >All prototypes (except those for static functions) must be Just a side note here. I hardly ever prototype static functions. I simply make sure that within a file a function is not used until it has been defined. This in effect makes it a prototype for itself. >or incautious programmers who are typing prototypes directly in >at the top of the .c files in which they are needed. (Programming >textbooks usually talk about functions before they talk about >#include, so their early examples suggest and reinforce this Which means that the methods of teaching C may need some overhaul. >I'm not trying to start a lint vs. prototypes flamefest here. Neither am I. I hope that this doesn't come across as some sort of personal attack. I do agree with a lot of what you say and I have no problem with those who are comfortable with lint using it. I simply happen to believe that there is a lot of value in prototypes and wanted to show that there was another side to the question. >Prototypes have their advantages, and they're definitely here to >stay. But they're not a panacea. And neither is lint. In the end the real issue is the capability of the programmer using the tools. Use the ones that you are comfortable with and get to know them well. -- D'Arcy J.M. Cain (darcy@druid) | D'Arcy Cain Consulting | There's no government Toronto, Ontario, Canada | like no government! +1 416 424 2871 |