Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!wasatch!cs.utexas.edu!uunet!yale!leichter From: leichter@CS.YALE.EDU (Jerry Leichter (LEICHTER-JERRY@CS.YALE.EDU)) Newsgroups: comp.std.c Subject: Re: Variable arguments in macros Message-ID: <58345@yale-celray.yale.UUCP> Date: 25 Apr 89 17:16:05 GMT Sender: root@yale.UUCP Organization: Yale Computer Science Department, New Haven, Connecticut, USA Lines: 52 X-from: leichter@CS.YALE.EDU (Jerry Leichter (LEICHTER-JERRY@CS.YALE.EDU)) I proposed a way to do this - and an additional reason why it would be useful - a long time back, but I'm not sure just where. Here's the jist: Extend #define so that #define f(a,b, ...) is allowed. When used as a macro, f must have at least two arguments, but it may have any number of additional ones. (The syntax is intended to be exactly like that for functions with variable numbers of arguments.) Within the definition of a macro taking a variable number of arguments, the fixed arguments may be used as usual. In addition, two built-in macros are available: _REST_ expands to the list of remaining arguments, including a leading comma if there is at least one such argument; and _NARGS_ expands to the total number of arguments passed. Thus: #define f(a,b, ...) g(_NARGS_,a,b _REST_) f(1,2,3,4) ==> g(4,1,2 ,3,4) f(1,2) ==> g(2,1,2 ) f(1) ==> For consistency, _REST_ and _NARGS_ should be available in any macro expan- sion; _REST_ will be empty, and _NARGS_ will be the count of arguments (0 for a macro taking no arguments). (The ugliest part of this is the need to include the leading comma in _REST_, and then omit it using _REST_ in an argument list. If you don't do that, however, you have to use: #define f(a,b, ...) g(_NARGS_,a,b,_REST_) f(1,2) ==> g(2,1,2,) which is erroneous. Of course, we could allow extraneous comma's in function calls (and declarators, for consistency)....) While this makes it easy to write macros calling fprintf and such, the main reason it is nice is that it provides a portable, efficient way to get the effect of the old nargs() call. It's very useful to be able to determine how many arguments you have been called with. For example, it allows you to extend a function by adding additional arguments without making previous uses stop working. It would also allow a function like fprintf, if it chose, to check for the sanity of the arguments it was given - it would be useful to have a debugging version of fprintf which told you that you hadn't matched the number of arguments and the number of specifiers. The objection that's been raised to requiring an nargs() facility is that it can be expensive on some architectures and most functions don't need it. With the macro facility I'm proposing, you can add the support yourself for exactly those functions where it's important to you. -- Jerry