ISO/IEC JTC1/SC22/WG14 N580 Proposal UK010b - variable argument lists for function-like macros ================================================================== Summary ------- This proposal provides a facility to allow function-like macros to have variable length argument lists. The proposal simply allows the trailing arguments to be substituted as a block. Two alternatives for the syntax are proposed; the semantics are the same in both cases. Conformance ----------- No C89 strictly conforming program should be affected by this proposal. Discussion ---------- The printf function in C89 is a special case of the fprintf function. In other such special cases, it is possible to write a macro that substitutes the general case for the special. However, this cannot be done for printf because it is a varargs function. This proposal allows the author of a macro to state that it takes a variable number of arguments, and to substitute the trailing arguments en bloc. A variation of the varargs notation is used. For example: #define printf(args ...) fprintf(stdout, args) in the first proposed syntax, or #define printf(... args) fprintf(stdout, args) in the second. It would be possible to provide further facilities, but this has been left for further proposals. One issue is whether it should be possible to allow zero actual arguments to match the trailing parameter. It has been decided not to allow this, as this fits better with another proposal being made separately. Detailed proposal ----------------- The following changes are common to both variants ------------------------------------------------- In subclause 6.8.3, replace the constraint: The number of arguments in an invocation of a function-like macro shall agree with the number of parameters in the macro definition, and there shall exist a ) preprocessing token that terminates the invocation. with If there is no ... in the identifier-list in the macro definition, the number of arguments in an invocation of a function-like macro shall agree with the number of parameters in the macro definition. Otherwise, there shall be at least as many arguments in the invocation as there are parameters in the macro definition. There shall exist a ) preprocessing token that terminates the invocation. Add after the last paragraph of the Semantics: If there is a ... in the identifier-list in the macro definition, then the trailing arguments, including their separating comma preprocessing tokens, are merged to form a single argument for the purposes of the following subclauses. The number of arguments so combined is such that, following merger, the number of arguments is the same as the number of parameters in the macro definition. In the examples following subclause 6.8.3.5, change the initial text of example 5 to: 5. To demonstrate the redefinition rules, The following changes apply to the first syntax variant only ------------------------------------------------------------ In subclause 6.8 Syntax, add a further alternative to control-line: # define identifier lparen identifier-list ... ) replacement-list new-line ------ --- - (literal tokens are underlined). In the examples following subclause 6.8.3.5, add a new example 6: 6. Finally, to show the variable argument list facilities: #define debug(args ...) fprintf(stderr, args) #define showlist(list ...) puts(#list) #define report(test, error ...) (test ? puts(#test) : printf(error)) debug("Flag"); debug("X = %d\n", x); showlist(The first, second, and third items.); report(x>y, "x is %d but y is %d", x, y); results in: fprintf(stderr, "Flag"); fprintf(stderr, "X = %d\n", x); puts("The first, second, and third items."); (x>y ? puts (x>y) : printf ("x is %d but y is %d", x, y)); The following changes apply to the second syntax variant only ------------------------------------------------------------- In subclause 6.8 Syntax, further alternatives to control-line: # define identifier lparen ... identifier ) replacement-list new-line ------ --- - # define identifier lparen identifier-list , ... identifier ) ------ - --- - replacement-list new-line (literal tokens are underlined). In the examples following subclause 6.8.3.5, add a new example 6: 6. Finally, to show the variable argument list facilities: #define debug(... args) fprintf(stderr, args) #define showlist(... list) puts(#list) #define report(test, ... error) (test ? puts(#test) : printf(error)) debug("Flag"); debug("X = %d\n", x); showlist(The first, second, and third items.); report(x>y, "x is %d but y is %d", x, y); results in: fprintf(stderr, "Flag"); fprintf(stderr, "X = %d\n", x); puts("The first, second, and third items."); (x>y ? puts (x>y) : printf ("x is %d but y is %d", x, y));