Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!cs.utexas.edu!uunet!yale!leichter From: leichter@CS.YALE.EDU (Jerry Leichter) Newsgroups: comp.std.c Subject: Re: Variable arguments in macros Message-ID: <59152@yale-celray.yale.UUCP> Date: 2 May 89 14:51:27 GMT Sender: root@yale.UUCP Organization: Yale Computer Science Department, New Haven, Connecticut, USA Lines: 79 X-from: leichter@CS.YALE.EDU (Jerry Leichter (LEICHTER-JERRY@CS.YALE.EDU)) In article <12839@haddock.ima.isc.com>, (Karl Heuer) writes... >In article <58345@yale-celray.yale.UUCP> (Jerry Leichter) writes: >>[allow an ellipsis in the macro parameters, and have a builtin macro _REST_ >>which] expands to the list of remaining arguments, including a leading comma >>if there is at least one such argument. > >Not good enough. Consider: > #define f(a,b,...) (g(a,b),h(_REST_)) >in which, for syntactic correctness, _REST_ must exclude the leading comma. >I suspect this was the major reason that variadic macros didn't make it into >the Standard: there was no clean proposal that handled the case with zero >additional args. There are two answers to this complaint: a) So what? What you've shown is that the facility I'm proposing is not as general as it might be. That's true of many parts of C's macro facility: It has enough power to do certain simple jobs, but no more. b) Actually, however, a detailed analysis shows that your example is wrong anyway. Look more closely at h. Whether h is a function or a macro, it is impossible for it to be correctlly callable with either no arguments OR with at least one argument. Both ANSI C "variadic" functions, and the "variadic" macros that I'm proposing, MUST be called with at least one argument. Hence, correct uses of f MUST have at least three arguments, and we can simply rewrite f as: #define f(a,b,c,...) (g(a,b),h(c _REST_)) - a formulation which has the additional advantage of generating more consis- tent and meaningful error messages, always reporting that it is f, which the programmer wrote, which was called with the wrong number of arguments, rather than a function h he may never have heard of. This argument generalizes: If you use _REST_ in specifying the arguments to a macro or function, the only problem you can run into is if _REST_ comes first, just after the "(". But then it cannot be the whole argument list, by the reasoning which applied to h. So you CAN construct examples which fail, like: #define f(a,b,...) (g(a,b),h(_REST_,NULL)) If this really worries you, I claim it shouldn't - you've defined the wrong calling convention for h. It would be much better to re-define h so that #define f(a,b,...) (g(a,b),h(_NARGS_ _REST_)) is the right calling sequence. If you look at all places in C where a comma makes sense, you can quickly find all the possible problems: 1. Comma operator: If you wanted: a = (_REST_) just write a = (0 _REST_) instead. 2. Function and macro argument lists - I've already discussed this. 3. Initializer lists. Again, you can probably construct plausible examples, most of which have plausible workarounds. The facility I'm proposing is simple and useful. Sure, you can add bells and whistles - just having both _REST_ (with leading comma) and _NREST_ (no lead- ing comma) will do it. (Or do you also need _EREST_, with the comma at the end?) Or you could add a pre-processor ?: operator - I might be able to write stuff like: #define f(a,b,...) (g(a,b),h((_NARGS_ > 0) #? (_REST_) #: (,) NULL)) (This might be better done as an ifthenelse pre-defined macro.) But all this goes way beyond what's needed to solve a significant problem which is not currently solvable in a clean way - as the discussion of the 2- vs. 3-argument BSD open() makes clear. -- Jerry