Path: utzoo!utgpu!news-server.csri.toronto.edu!mailrus!uwm.edu!zaphod.mps.ohio-state.edu!samsung!uunet!island!grenada!christmas!rtm From: rtm@christmas.UUCP (Richard Minner) Newsgroups: comp.lang.c Subject: Re: selectively enabling prototypes Summary: a better version, both break C syntax Message-ID: <7@christmas.UUCP> Date: 17 Aug 90 00:10:53 GMT References: <493@mtndew.Tustin.CA.US> Reply-To: rtm@island.uu.net (Richard Minner) Followup-To: comp.lang.c Organization: Island Graphics, Sacramento, California Lines: 81 In article <493@mtndew.Tustin.CA.US>, Steve Friedl writes: > > I like to use function prototypes when possible, so... > #ifdef USE_PROTO > # define PROTO(name, args) name args > #else > # define PROTO(name, args) name ( ) > #endif >... > However, I have seen it done "the hard way": > #ifdef USE_PROTO > extern int printf(const char *, ... ); >... > This looks like a real maintenance nightmare, but some of the > people who do it are people I respect, so I gotta wonder if they > know something that I don't know on this one. Are there any > gotchas on doing it with the flavor of the way I've done it? First, one caution that some may still not be aware of (even though it's covered in the FAQ, question 22 :-), which is, briefly, that with Classic style function declarations and definitions, args of type char, short and float are (silently) promoted to int and double, whereas with ANSI style they are not, e.g: extern int foo(char c); ... int foo(c) char c; doesn't work. Those who don't understand should read FAQ, Q #22 (or thereabouts). So you can't use your PROTO() macro with functions that take char's, short's or float's as arguments. Other than that, it *works* fine (see end of article). In fact, the "updated version of the `Indian Hill C Style and Coding Standards'" (which was posted here a while back, and by the way, thanks!), includes a `PROTO()' macro similar to yours, like this: #ifdef HAVE_ANSI_PROTOTYPES # define PROTO(args) args #else # define PROTO(args) () #endif I find this much cleaner, because the results look (to me) more like normal declarations, and because it supports things like signal() (and I use a fair number of `functions taking functions as arguments'). It takes advantage of the fact that the only difference between ANSI prototypes and Classic decls is the presence of the argument list. I actually use `P_()', because it's much more cryptic and hard to read ;-), so signal() would look like: extern void ( *signal P_((int sig, void (*func)(int))) ) P_((int)); which is admittedly a bit ugly with all the ()'s, but: #ifdef HAVE_ANSI_PROTOTYPES extern void (*signal (int sig, void (*func)(int))) (int); #else extern void (*signal())(); #endif isn't much of an improvement. By the way, don't forget typedefs, e.g: typedef int (*func_type) P((int, double, const char *)); As to why some experienced programmers would use the `#if' approach instead, it's probably because they don't like macros that alter the syntax of C, which is *not* an unreasonable position, mind you. It's your code, you choose. Just don't be surprised if someone someday is irritated by it. I can't imagine any other reasons to prefer `#if'. -- Richard Minner || {uunet,sun,well}!island!rtm (916) 736-1323 || || Island Graphics Corporation Sacramento, CA ||