u5565522@ucsvc.unimelb.edu.au (David Clunie) (08/31/88)
How do people feel about the idea of preprocessor macros with variable length argument lists ? The concept has already been enshrined for true functions, allowing protoypes for things like the printf() family of functions, and a set of portable functions and macros to access the list of arguments. However this can not be done with macro calls. Wouldn't it be nice to be able to do something like ... #ifdef TRACE #define tracef(s,...) printf(s,...) #else #define tracef(s,...) /* nothing */ #endif At present, this CANNOT BE DONE, without nesting parentheses (clumsy) or using a call to an empty function (inefficient, unless you have inline integration in an optimizing compiler). Just a thought. Probably a bit late for the ANSI standard. I am certainly going to put it in my compiler though !!! Regards ... David Clunie
gwyn@smoke.ARPA (Doug Gwyn ) (09/01/88)
In article <438@ucsvc.unimelb.edu.au> u5565522@ucsvc.unimelb.edu.au (David Clunie) writes: >Just a thought. Probably a bit late for the ANSI standard. It was brought up, thoroughly discussed, and eventually rejected by X3J11.
rss@ece-csc.UUCP (ML) (09/01/88)
In a previous article u5565522@ucsvc.unimelb.edu.au (David Clunie) wrote: >How do people feel about the idea of preprocessor macros with variable >length argument lists ? I for one would love it. Plenty of times I've wanted macros like: #define trace(...) if (TraceFlag) fprintf(stderr, ...) #define crash(rc,...) { fprintf(stderr,...); return(rc); } etc. etc. This seems like it would be a simple and useful addition to the preprocessor, and one which could be implemented in a fairly painless way. Would it really be that difficult to add to the standard? (No flames please, that's a serious question based upon my own ignorance :-) One yes vote here... Mark Lanzo borrowing ...!mcnc!ece-csc!rss
lvc@cbnews.ATT.COM (Lawrence V. Cipriani) (09/01/88)
In article <438@ucsvc.unimelb.edu.au>, u5565522@ucsvc.unimelb.edu.au (David Clunie) writes: > How do people feel about the idea of preprocessor macros with variable > length argument lists ? I'd like it, but its not essential. I don't mind using double parenthesis to fake out the preprocessor. > However this can not be done with macro calls. Wouldn't it be nice to be > able to do something like ... > > #ifdef TRACE > #define tracef(s,...) printf(s,...) > #else > #define tracef(s,...) /* nothing */ > #endif > > At present, this CANNOT BE DONE, without nesting parentheses (clumsy) or > using a call to an empty function (inefficient, unless you have inline > integration in an optimizing compiler). Only clumsy for the uncoordinated :-) You missed one more way: #ifdef TRACE #define trace(anything) anything #else #define trace(anything) #endif and you use it like this: c(i) { trace( if (i == 0) printf("boom\n");) } The only restriction I can think of now is that you'll have to be careful how the comma operator is used. -- Larry Cipriani, AT&T Network Systems, Columbus OH, cbnews!lvc lvc@cbnews.ATT.COM
gsf@ulysses.homer.nj.att.com (Glenn Fowler[eww]) (09/01/88)
In article <438@ucsvc.unimelb.edu.au>, u5565522@ucsvc.unimelb.edu.au (David Clunie) writes: > ... Wouldn't it be nice to be able to do something like ... > #ifdef TRACE > #define tracef(s,...) printf(s,...) > #else > #define tracef(s,...) /* nothing */ > #endif > ... Probably a bit late for the ANSI standard ... too late, but here is the description of macro `...' args for a local preprocessor extension: If the last formal argument is followed by the `...' token then it is replaced by the expanded value of all remaining actual arguments and intervening `,' tokens from the macro call. If there is only one formal argument then the macro may be called with no actual arguments, otherwise there must be at least one actual argument for the last formal argument. this would change the tracef() macro definition to #define tracef(s,...) printf(s) the `,' before the `...' is optional to satisfy all tastes -- Glenn Fowler AT&T Bell Laboratories, Murray Hill {ihnp4,allegra}!ulysses!gsf (201)-582-2195
peter@thirdi.UUCP (Peter Rowell) (09/02/88)
If the reason for variable arguments is to pass them to a routine that takes varargs, the following horrible hack seems not only to work but to be portable! #define d_printf(level, stuff) ((level>=debug_level)? printf stuff :level=level) Note: NO parentheses --> ^ ^ This is then invoked by: d_printf(8, ("foo overflow: %d > %d", some_foo, max_foo)); ^ <----- Note the parentheses -----------> ^ By placing parentheses around the args for printf, they become 1 arg from the point of view of the macro expander. The reason for the ?: usage is to allow this "if" anywhere a single expression could be without screwing up things like: if (cond) d_printf(x,("bummer")); else somehthingelse; ---------------------------------------------------------------------- Peter Rowell (You will need a bigger rock.) Third Eye Software, Inc. (415) 321-0967 Menlo Park, CA 94025 ...!pyramid!thirdi!peter
davidra@batcomputer.tn.cornell.edu (David A. Rabson) (09/02/88)
(Summary: people complain about lack of variable-length arg lists for macros. Standards people try to cover themselves. Other people point out that (( ... )) often works almost as well as variable-length arg list.) There is another way to fake out at least some preprocessors. I find the following useful in header files. The header file is included in several code files only one of which defines GLOBALS. #undef INIT #undef COMMA #define COMMA , #ifdef GLOBALS #define INIT(x) =x #else #define INIT(x) /*nop*/ #endif extern int x[2] INIT({1 COMMA 2}); Since the (( )) and COMMA kludges cover all the cases where I might have wanted variable-length argument lists in cpp macros, I have to agree that the extension would be unnecessary David Rabson Laboratory of Atomic and Solid State Physics
d85_kitte@tekn01.chalmers.se (Kristian Wedberg) (09/02/88)
In article <438@ucsvc.unimelb.edu.au>, u5565522@ucsvc.unimelb.edu.au (David Clunie) writes: > How do people feel about the idea of preprocessor macros with variable > length argument lists ? > > The concept has already been enshrined for true functions, allowing > protoypes for things like the printf() family of functions, and a set of > portable functions and macros to access the list of arguments. > > However this can not be done with macro calls. Wouldn't it be nice to be > able to do something like ... > > > #ifdef TRACE > > #define tracef(s,...) printf(s,...) > > #else > > #define tracef(s,...) /* nothing */ > > #endif > ... > Regards ... David Clunie My solution for the debugging-part of this is to use several macros. The following is a (very) small extract from my debug-includefile: #ifndef DEBUG_H #define DEBUG_H /* name: debug.h * * description: Header-file with debug-macros & prototypes. * pr(text) : print text (no " " or \n, & NO COMMAS!) pr0("..\n") - pr6(...) : print string (with 0 - 6 arguments) * * problems: * ??? No commas in pr() ??? */ /* pr(), pr1() -> pr6() * Produces no code when NPRINTING is defined! Just an empty statement * from the semicolon. */ /* Print without arguments. "..." NOT needed */ #ifndef NPRINTING #define pr(s) printf("s\n") #else #define pr(x) #endif /* Print with 0 to 6 arguments & "...\n" */ #ifndef NPRINTING #define pr0(s) printf(s) #define pr1(s,a1) printf(s,a1) #define pr1(s,a1) printf(s,a1) #define pr2(s,a1,a2) printf(s,a1,a2) #define pr3(s,a1,a2,a3) printf(s,a1,a2,a3) #define pr4(s,a1,a2,a3,a4) printf(s,a1,a2,a3,a4) #define pr5(s,a1,a2,a3,a4,a5) printf(s,a1,a2,a3,a4,a5) #define pr6(s,a1,a2,a3,a4,a5,a6) printf(s,a1,a2,a3,a4,a5,a6) #else #define pr0(x) #define pr1(x,x1) #define pr2(x,x1,x2) #define pr3(x,x1,x2,x3) #define pr4(x,x1,x2,x3,x4) #define pr5(x,x1,x2,x3,x4,x5) #define pr6(x,x1,x2,x3,x4,x5,x6) #endif Hope you'll find it useful... Kristian Wedberg
gregg@ihlpb.ATT.COM (Wonderly) (09/02/88)
From article <1036@cbnews.ATT.COM>, by lvc@cbnews.ATT.COM (Lawrence V. Cipriani): ] In article <438@ucsvc.unimelb.edu.au>, u5565522@ucsvc.unimelb.edu.au (David Clunie) writes: ] ] .... ] ]> However this can not be done with macro calls. Wouldn't it be nice to be ]> able to do something like ... ]> ]> #ifdef TRACE ]> #define tracef(s,...) printf(s,...) ]> #else ]> #define tracef(s,...) /* nothing */ ]> #endif ]> ]> At present, this CANNOT BE DONE, without nesting parentheses (clumsy) or ]> using a call to an empty function (inefficient, unless you have inline ]> integration in an optimizing compiler). ] ] Only clumsy for the uncoordinated :-) You missed one more way: ] ] #ifdef TRACE ] #define trace(anything) anything ] #else ] #define trace(anything) ] #endif ] ] and you use it like this: ] ] c(i) ] { ] trace( if (i == 0) printf("boom\n");) ] } I always use the following #ifdef DEBUG #define debug(x,y) {if (x > debuglvl) printf y}; #else DEBUG #define debug(x,y) #endif DEBUG This gets you something like the above, although it does not allow arbitrary values or conditions to govern the printing or execution of debug information/code. In general though I seldom need other conditions to govern the debug output because I try to check all of the conditions where things might go wrong anyway so I would write the above as... c(i) { if (i == 0) { debug (1, ("OOOPS i == %d\n", i)); abort(); } } Gregg Wonderly AT&T Bell Laboratories DOMAIN: gregg@ihlpb.att.com IH2D217 - (312) 979-2794 UUCP: ihnp4!ihlpb!gregg -- Gregg Wonderly AT&T Bell Laboratories DOMAIN: gregg@ihlpb.att.com IH2D217 - (312) 979-2794 UUCP: ihnp4!ihlpb!gregg
meissner@xyzzy.UUCP (Michael Meissner) (09/03/88)
In article <438@ucsvc.unimelb.edu.au> u5565522@ucsvc.unimelb.edu.au (David Clunie) writes: | How do people feel about the idea of preprocessor macros with variable | length argument lists ? | | The concept has already been enshrined for true functions, allowing | protoypes for things like the printf() family of functions, and a set of | portable functions and macros to access the list of arguments. As Doug mentioned this has come before the ANSI committee and did not get the necessary 2/3 vote to get it in. Let me mention something that came up in our discussion: Namely that it is desirable that you have two different forms of this, one for the times that you want the comma supplied if there are extra arguments, and the other for times when you don't want the comma. Otherwise you could get compilation errors if no extra arguments were passed. -- Michael Meissner, Data General. Uucp: ...!mcnc!rti!xyzzy!meissner Arpa: meissner@dg-rtp.DG.COM (or) meissner%dg-rtp.DG.COM@relay.cs.net
scs@itivax.UUCP (Steve C. Simmons) (09/06/88)
In article <1036@cbnews.ATT.COM> lvc@cbnews.ATT.COM (Lawrence V. Cipriani) writes: -In article <438@ucsvc.unimelb.edu.au>, u5565522@ucsvc.unimelb.edu.au (David Clunie) writes: -> How do people feel about the idea of preprocessor macros with variable -> length argument lists ? -> -> At present, this CANNOT BE DONE, without nesting parentheses (clumsy) or -> using a call to an empty function (inefficient, unless you have inline -> integration in an optimizing compiler). - -Only clumsy for the uncoordinated :-) You missed one more way: - - #ifdef TRACE - #define trace(anything) anything - #else - #define trace(anything) - #endif - -and you use it like this: - - c(i) - { - trace( if (i == 0) printf("boom\n");) - } - -The only restriction I can think of now is that you'll have to be careful -how the comma operator is used. - -Larry Cipriani, cbnews!lvc lvc@cbnews.ATT.COM A nice hack, but one additional word of warning -- the disappearing line of code can cause some interesting and obscure bugs. I had one program that worked with the trace code but failed oddly without it. The exact form escapes me, but it was something like . . . if ( x == m ) trace( printf( "the consequences\n) ; ) froob( some function ) ; This produced rather different programs depending on the definition of 'trace'! -- Steve Simmons ...!umix!itivax!vax3!scs Industrial Technology Institute, Ann Arbor, MI. "You can't get here from here."
merlyn@rose3.rosemount.com (Brian Westley) (09/06/88)
There is a way to do this, but it's ugly, dangerous, noisy, and not portable... short _NARGS_; #define max(a,b,c,d,e) \ (_NARGS_=5,-a-_NARGS_,-b-_NARGS_,-c-_NARGS_,-d-_NARGS_,-e-_NARGS_,\ _max(_NARGS_,a-0,b-0,c-0,d-0,e-0)) main() { int x,y; printf("%d ",max(3,5,4)); x = max((-9),(-11),2*6-55); y = max(4,2-x,(-6),999,5-9); printf("%d %d %d\n",x,y,max(x,y-3)); } _max(n,a,b,c,d,e) int n; int a,b,c,d,e; { int result; result = a; if (--n>0 && b>result) result=b; if (--n>0 && c>result) result=c; if (--n>0 && d>result) result=d; if (--n>0 && e>result) result=e; return result; } ---- Merlyn LeRoy
haahr@phoenix.Princeton.EDU (Paul Gluckauf Haahr) (09/08/88)
> How do people feel about the idea of preprocessor macros with variable > length argument lists ? > > However this can not be done with macro calls. Wouldn't it be nice to be > able to do something like ... > > > #ifdef TRACE > #define tracef(s,...) printf(s,...) > #else > #define tracef(s,...) /* nothing */ > #endif > > At present, this CANNOT BE DONE, without nesting parentheses (clumsy) or > using a call to an empty function (inefficient, unless you have inline > integration in an optimizing compiler). well, if your trace function has no more arguments than printf, you can always do #ifdef TRACE #define tracef printf #else #define tracef 1 ? 0 : #endif note the complete absence of parenthese. if you want arguments, the syntax gets ugly, but can work. for example, #ifdef TRACE #define trace(n) (debug > n) ? 0 : printf #else #define trace(n) 1 ? 0 : #endif usage is then trace(3)("n = %d\n", n) making that print to stderr probably requires an additional function call, but only when tracing is enabled. [ this trick is not my own. peter honeyman (now umix!honey) showed me a variant in 1984 that is in the hdb uucp sources, used to implement logging for uucico -x<number> ] paul haahr princeton!haahr haahr@princeton.edu
jones@ingr.UUCP (Mark Jones) (09/08/88)
In article <3604@phoenix.Princeton.EDU>, haahr@phoenix.Princeton.EDU (Paul Gluckauf Haahr) writes: > > How do people feel about the idea of preprocessor macros with variable > > length argument lists ? > > > > However this can not be done with macro calls. Wouldn't it be nice to be > > able to do something like ... > > > > > > #ifdef TRACE > > #define tracef(s,...) printf(s,...) > > #else > > #define tracef(s,...) /* nothing */ > > #endif > > > > At present, this CANNOT BE DONE, without nesting parentheses (clumsy) or > > using a call to an empty function (inefficient, unless you have inline > > integration in an optimizing compiler). If you want a trace function, try this one #ifdef TRACE #define TR(x) x #else #define TR(x) #endif Now, you can just say . . . TR(printf("entering buggy function")); . . . and all is well! Bought from Dr Dobbs Journal, Only good thing to come out of that magazine in months.(Did BYTE buy them out?) <-- Rhetorical question Mark Jones
walker@island.uu.net (Richard Walker) (09/15/88)
In article <228@itivax.UUCP> scs@itivax.UUCP (Steve C. Simmons) writes: >In article <1036@cbnews.ATT.COM> lvc@cbnews.ATT.COM (Lawrence V. Cipriani) writes: >-In article <438@ucsvc.unimelb.edu.au>, u5565522@ucsvc.unimelb.edu.au (David Clunie) writes: >- >- #ifdef TRACE >- #define trace(anything) anything >- #else >- #define trace(anything) >- #endif >- > if ( x == m ) > trace( printf( "the consequences\n) ; ) > froob( some function ) ; > >This produced rather different programs depending on the definition of >'trace'! The problem illustrated above is caused by the bad usage of the macro. The macro call should be formed as a statement to avoid the flow control problem. In other words, the errors above are caused by the missing ';' at the end of the trace macro call. Especially, macros which expand into code with flow control should be formed such that the semicolon cleanly terminates the flow, e.g.: #define COMPLEX_MACRO(foo) (if(SOME_TEST(foo)) {statements;}else) Then the correct usage of COMPLEX_MACRO would be: COMPLEX_MACRO(foo); which also handles the case where COMPLEX_MACRO expands into nothing. cat <flames_about_crufty_usage_of_code_in_macros >/dev/null
chris@mimsy.UUCP (Chris Torek) (09/15/88)
In article <362@island.uu.net> walker@island.uu.net (Richard Walker) suggests that >... macros which expand into code with flow control >should be formed such that the semicolon cleanly terminates >the flow, e.g.: > >#define COMPLEX_MACRO(foo) (if(SOME_TEST(foo)) {statements;}else) This works (after correcting the syntax), but I recommend instead #define MAC() if (!(normal_test)) /*void*/; else mac_statement or, if you need {}s, #define MAC() do { mac_statements } while (0) These have the advantage over the one above that MAC() /* missing semicolon */ next_stmt; produces a syntax error, rather than code that reads if (some_test) { statements; } else next_stmt; -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
scjones@sdrc.UUCP (Larry Jones) (09/16/88)
In article <362@island.uu.net>, walker@island.uu.net (Richard Walker) writes: > The problem illustrated above is caused by the bad usage of the macro. The > macro call should be formed as a statement to avoid the flow control problem. > In other words, the errors above are caused by the missing ';' at the end > of the trace macro call. > > Especially, macros which expand into code with flow control > should be formed such that the semicolon cleanly terminates > the flow, e.g.: > > #define COMPLEX_MACRO(foo) (if(SOME_TEST(foo)) {statements;}else) Well, it's a good idea, but the example could be better - it could be valid C if the replacement text didn't have the parentheses around a partial statement! In any case, the preferred definition of statement macros is: #define COMPLEX_MACRO(foo) do { whatever } while (0) That way the macro expands into a single statement, eats the following semi- colon, and causes a syntax error if there isn't one instead of accidentally swallowing the following statement. ---- Larry Jones UUCP: uunet!sdrc!scjones SDRC scjones@sdrc.uucp 2000 Eastman Dr. BIX: ltl Milford, OH 45150 AT&T: (513) 576-2070 "Save the Quayles" - Mark Russell
david@sun.uucp (David DiGiacomo) (09/16/88)
In article <13573@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes: >or, if you need {}s, > > #define MAC() do { mac_statements } while (0) That's nice, but lint churlishly complains about "constant in conditional context". To avoid this, use: #ifdef lint int _ZERO_; #else #define _ZERO_ 0 #endif #define _STMT(op) do { op } while (_ZERO_) #define MAC() _STMT(mac_statements)
jones@ingr.UUCP (Mark Jones) (09/16/88)
In article <228@itivax.UUCP> scs@itivax.UUCP (Steve C. Simmons) writes: >In article <1036@cbnews.ATT.COM> lvc@cbnews.ATT.COM (Lawrence V. Cipriani) writes: >-In article <438@ucsvc.unimelb.edu.au>, u5565522@ucsvc.unimelb.edu.au (David Clunie) writes: >- >- #ifdef TRACE >- #define trace(anything) anything >- #else >- #define trace(anything) >- #endif >- > if ( x == m ) > trace( printf( "the consequences\n) ; ) > froob( some function ) ; > This produced rather different programs depending on the definition of 'trace'! Try rephrasing it as if(x == m) trace(printf("the consequences\n")); ^ ^ ^ This will evaluate to: if(x == m) ; or if(x == m) printf("the cosequences\n"); which will not affect the surrounding code.
karl@haddock.ima.isc.com (Karl Heuer) (09/17/88)
The original question in this thread, concerning an idea for compiler support for variadic macros, was appropriate for comp.std.c. The stream of replies that look like `This is how I like to work around the problem' are not; these should be confined to comp.lang.c. Please stop the crossposting. Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint