Stifletypes: Why Bother With Prototypes?
29 March, 2002
Why bother with function prototypes? Seriously, if you're just going to stick a function prototype into the C file to stifle the warning (I'm going to call this a "stifletype"), you might as well drop the warning level on your compiler to the point where it stops complaining about missing prototypes.
If the preceding paragraph describes you and are attempting to write C++, I'd suggest sticking to straight C. If you're going to shoot yourself in the foot, you might as make a nice, clean hole just behind the toes (C) rather than blowing your leg off from the knee down (C++).
The whole point of a function prototype is so that the compiler can perform type checking. This means that every time you call a function the compiler checks the number of arguments, the types of all of the arguments, and the type of the return value. The compiler also checks the function definition to make sure that it matches the prototype.
When you create a stifletype, you lose all of those checks. Here are some common scenarios:
- The stifletype matches the function definition. In this case, everything works fine. This happens occasionally, perhaps even often.
- The stifletype matches the function definition when it is initially added to the C file, but the function definition later changes. (Perhaps this was to add an additional argument, or maybe the type of one of the arguments changed). The compiler won't complain about an argument type (or argument count) mismatch on calls from the C file containing your stifletype. Consider what could happen if the function adds an additional pointer argument. Your calls will not provide this argument in the call, and the function will use whatever value happens to be on the stack. This might crash your program -- but that's just a best case scenario. Worse would be that the function just scribbles into some arbitrary memory location. These kinds of errors can be very difficult to track down.
- The stifletype matches the function definition initially, but the function is later removed. (Perhaps because it has been replaced by one or more similar functions; possibly during a refactoring.) This is likely to produce a link error. Sometimes these can be difficult to track down; if it isn't obvious from the stifletype where the function was previously defined then you'll have some detective work ahead.
- The stifletype never matches the function definition. Probably because of a simple transcription error or maybe because of a misunderstanding of the order of arguments. (Does memset() go "dest, value, len" or "len, value, dest"?)
- The calls that require the stifletype are removed or changed. Over time, your C file will fill up with a bunch of extraneous stifletypes. Nobody wants to remove them because it just seems like too much work.
- The stifletype is correct on the current platform, but it is not portable. Everything works fine when you build for x86-linux, but croaks horribly when you build for sparc-solaris. Portability is hard enough; using stifletypes will just make your life much worse than it needs to be.
What's more, why bother doing extra work when you're deriving no benefit from it? If you think about it, it is harder to add a stifletype than it is to add an #include. First, there is more typing involved:
- #include <SomeHeader.h> /* 23 characters */
- extern void SomeFunction(int, int); /* 35 characters */
Second, there is more effort involved in actually finding the function definition and copying the prototype than there is in finding the header file with the appropriate prototype.
The only case that I can think of that seems like more work, is the case where you need to use a function that isn't prototyped in a header file. However, if you think about the possibility that this function will be called from other source files, you're investing a little up-front work to reduce the amount of work required later on. So just add the prototype to the appropriate header file, or create a new one if necessary.
The alternative is to turn off the warnings on your compiler, roll up your sleeves, and get ready for some fun debugging sessions.