lgy@pupthy2.PRINCETON.EDU (Larry Yaffe) (05/12/88)
Are there any versions of cpp which allow one to define macros which accept variable numbers of arguments? I keep wishing for this every time I try to move code developed using sysV sprintf to a BSD system, so that I could do something like: #ifdef BSD_TO_5_SPRINTF char *(*Sprintf)() = sprintf ; #define sprintf(...) strlen (Sprintf (...)) #endif #ifdef 5_TO_BSD_SPRINTF int (*Sprintf)() = sprintf ; #define sprintf(str,...) ((void) Sprintf (str,...), str) #endif I know that some systems have `vsprintf' or some such thing which can be called from a sprintf replacement routine, but since the vprintf routines are not universally available (sadly), using them seems only to add to portability problems. Does anyone know why the folks at Berkeley chose to have their sprintf return its first argument, instead of the number of characters printed? I can't think of any good reason for this choice, since it throws away valuable information (the # of characters printed) which is painful to reacquire. On a separate topic: How common is the ability to initalize unions? (In C, of course.) Did this make it into the ANSI specs? ------------------------------------------------------------------------ Laurence G. Yaffe lgy@pupthy.princeton.edu Department of Physics lgy@pucc.bitnet Princeton University ...!princeton!pupthy!lgy PO Box 708, Princeton NJ 08544 609-452-4371 or -4400
guy@gorodish.Sun.COM (Guy Harris) (05/12/88)
> Are there any versions of cpp which allow one to define macros which > accept variable numbers of arguments? None that I know of. There are tricks that can be used for this: #define Sprintf(x) sprintf x main() { char buf[40]; Sprintf((buf, "%d", 33)); Sprintf((buf, "%d %d", 33, 66)); } but this requires the extra layer of parentheses; I presume you want a "magic bullet" that requires few source changes to the program you're trying to convert. Neither K&R nor ANSI C have any syntax for macros of this sort. > I keep wishing for this every time I try to move code developed using sysV > sprintf to a BSD system, Your best bet here is just to redo the code not to depend on the return value of "sprintf". Sad, but true. > Does anyone know why the folks at Berkeley chose to have their > sprintf return its first argument, instead of the number of characters > printed? Nobody can possibly know that, because they weren't the ones who made that decision. "sprintf" worked that way in V7 (although I don't think it was so documented) - in fact, the System III SCCS code was written assuming this behavior, which is kind of amusing since the System III "sprintf" returned the number of characters generated.... (Some BSD/S5 differences are really V7/S5 differences; questions about why *those* differences exist should be directed to AT&T, since they were responsible for both systems.)
lvc@tut.cis.ohio-state.edu (Lawrence V. Cipriani) (05/12/88)
In article <2855@phoenix.Princeton.EDU>, lgy@pupthy2.PRINCETON.EDU (Larry Yaffe) writes: > > Are there any versions of cpp which allow one to define macros which > accept variable numbers of arguments? I keep wishing for this every time > I try to move code developed using sysV sprintf to a BSD system, so that > I could do something like: > examples deleted This question comes up now and then. No version of cpp I know has a variable count capability, but those are only AT&T cpp's. You can work around it though, so this is portable. Define a macro like this: #define SPRINTF(args) sprintf args and use it like this: SPRINTF((str, format, a1, a2, ..., an)); The double parens trick cpp into seeing only one argument. After cpp expansion you get: sprintf (str, format, a1, a2, ..., an); -- Larry Cipriani, AT&T Network Systems and Ohio State University Domain: lvc@tut.cis.ohio-state.edu Path: ...!cbosgd!osu-cis!tut.cis.ohio-state.edu!lvc (weird but right)
terryl@tekcrl.TEK.COM (05/14/88)
In article <2855@phoenix.Princeton.EDU+ lgy@pupthy2.PRINCETON.EDU (Larry Yaffe) writes:
+
+ Are there any versions of cpp which allow one to define macros which
+accept variable numbers of arguments? I keep wishing for this every time
+I try to move code developed using sysV sprintf to a BSD system, so that
+I could do something like:
+
+#ifdef BSD_TO_5_SPRINTF
+char *(*Sprintf)() = sprintf ;
+#define sprintf(...) strlen (Sprintf (...))
+#endif
+
+#ifdef 5_TO_BSD_SPRINTF
+int (*Sprintf)() = sprintf ;
+#define sprintf(str,...) ((void) Sprintf (str,...), str)
+#endif
I came across this kludge years ago, hope it helps:
#define sprintf(prf) { Sprintf prf }
The TRICK is to ADD an extra level of parentheses, using it like thus:
sprintf( (buffer,"<what-ever-string-you-want>",<varargs>) );
This makes cpp THINK there is only one argument to the macro; I know you
don't want to muck with the sources and just want to put in the #define
and be done with it, but this is the only way I know of.
+ I know that some systems have `vsprintf' or some such thing which
+can be called from a sprintf replacement routine, but since the vprintf
+routines are not universally available (sadly), using them seems only
+to add to portability problems.
+
+ Does anyone know why the folks at Berkeley chose to have their
+sprintf return its first argument, instead of the number of characters
+printed? I can't think of any good reason for this choice, since it
+throws away valuable information (the # of characters printed) which
+is painful to reacquire.
How painful is a strlen???? (I.E. I really don't understand your
complaint). Since Berkeley code is almost always derived upon ATT (or
whatever they're calling themselves this year!!! (-:) code, it sounds
like an earlier version of sprintf returned its first argument. However,
I also can't really think of any good reason for one return value over
the other.......
jgy@hropus.UUCP (John Young) (05/14/88)
> > > Are there any versions of cpp which allow one to define macros which > > accept variable numbers of arguments? I think that some of the AT&T CPLU compilers(cpp's) allow this, you just overdeclare the arguments: #define Dprintf(a,b,c,d,e,f,g,h,i) {if (Debug) printf(a,b,c,d,e,f,g,h,i);} and compile. You will get a warning about each source line which uses the wrong number of arguments.
lgy@pupthy2.PRINCETON.EDU (Larry Yaffe) (05/14/88)
In article <2633@tekcrl.TEK.COM> terryl@tekcrl.tek.com writes: >In article <2855@phoenix.Princeton.EDU+ (lgy@pupthy2.PRINCETON.EDU) I wrote: >+ >+ Are there any versions of cpp which allow one to define macros which >+accept variable numbers of arguments? I keep wishing for this every time >+I try to move code developed using sysV sprintf to a BSD system, so that >+I could do something like: [example deleted] > > I came across this kludge years ago, hope it helps: >#define sprintf(prf) { Sprintf prf } > > The TRICK is to ADD an extra level of parentheses, using it like thus: > > sprintf( (buffer,"<what-ever-string-you-want>",<varargs>) ); > >This makes cpp THINK there is only one argument to the macro; I know you >don't want to muck with the sources and just want to put in the #define Right!! >and be done with it, but this is the only way I know of. A number of people suggested variants of the above. Unfortunately, all of these approaches require manual editing of (large amounts of) existing source code. The whole point of the exercise is to be able to automate the conversion between sysV & BSD versions of sprintf. Regrettably, such a stupid little inconsistency (the difference in return values) cannot be automatically fixed using any combination of cpp, sed, or awk. Several other people pointed out that one shouldn't ever use the return value of sprintf if you want maximally portable code. True, but rewritting existing code is SO much fun :-). >+ Does anyone know why the folks at Berkeley chose to have their >+sprintf return its first argument, instead of the number of characters >+printed? I can't think of any good reason for this choice, since it >+throws away valuable information (the # of characters printed) which >+is painful to reacquire. > > How painful is a strlen???? (I.E. I really don't understand your >complaint). Well, since every implementation of sprintf I've seen counts the number of characters printed internally, its irritating if you have to call strlen just to recompute information that was easily available but thrown away. And its quite possible for the extra call to strlen to take nearly as long as the sprintf. If you're calling sprintf a LOT of times, adding a call to strlen after each sprintf can be very significant. ------------------------------------------------------------------------ Laurence G. Yaffe Internet: lgy@pupthy.princeton.edu Department of Physics Bitnet: lgy@pucc Princeton University UUCP: ...!princeton!pupthy!lgy PO Box 708, Princeton NJ 08544
ok@quintus.UUCP (Richard A. O'Keefe) (05/14/88)
In article <2855@phoenix.Princeton.EDU>, lgy@pupthy2.PRINCETON.EDU (Larry Yaffe) writes: > Does anyone know why the folks at Berkeley chose to have their > sprintf return its first argument, instead of the number of characters > printed? I can't think of any good reason for this choice, since it > throws away valuable information (the # of characters printed) which > is painful to reacquire. Berkeley left sprintf() as they found it; that's what it did in V7. There is an argument in favour of it: it makes it more like strcpy(). [Not that I think much of it, I've never found the return value of strcpy() useful.] What's so painful about calling strlen()?
ok@quintus.UUCP (Richard A. O'Keefe) (05/15/88)
In article <2886@phoenix.Princeton.EDU>, lgy@pupthy2.PRINCETON.EDU (Larry Yaffe) writes: > In article <2633@tekcrl.TEK.COM> terryl@tekcrl.tek.com writes: > >In article <2855@phoenix.Princeton.EDU+ (lgy@pupthy2.PRINCETON.EDU) I wrote: > >+ Are there any versions of cpp which allow one to define macros which > >+accept variable numbers of arguments?> > I came across this kludge years ago, hope it helps: > > The TRICK is to ADD an extra level of parentheses, using it like thus: > > sprintf( (buffer,"<what-ever-string-you-want>",<varargs>) ); > >This makes cpp THINK there is only one argument to the macro; I know you > >don't want to muck with the sources and just want to put in the #define > A number of people suggested variants of the above. Just a wild heretical suggestion, but there is *another* macro processor which comes standard with UNIX. System V has it and BSD has it, and there is a rather nice public domain version. I refer, of course, to m4. What I suggest is a one-time conversion: sprintf(S,F) -> sprintf0(S,F) sprintf(S,F,A) -> sprintf1(S,F,A) ... sprintf(S,F,A,B,C,D,E,F)-> sprintf6(S,F,A,B,C,D,E,F) however many you need. This is easy enough to do with m4. Then you write your cpp macros for each sprintfN, which is a bit of a pain, but means you don't have to keep using m4. It is precisely because m4 is there to fall back on when you need REAL macro-power that cpp can be so weak.
ok@quintus.UUCP (Richard A. O'Keefe) (05/15/88)
In article <979@cresswell.quintus.UUCP>, ok@quintus.UUCP (Richard A. O'Keefe) writes: > What I suggest is a one-time conversion: > sprintf(S,F) -> sprintf0(S,F) > sprintf(S,F,A) -> sprintf1(S,F,A) > ... > sprintf(S,F,A,B,C,D,E,F)-> sprintf6(S,F,A,B,C,D,E,F) > however many you need. This is easy enough to do with m4. I should substantiate that. cat >sprintf.m4 <<'EOF' define(sprintf,``sprintf'eval($#-2)($*)')dnl EOF This uses $# and $* which are in the System V and PD versions, but not in the BSD version, so you may have to do your conversion on System V. All it takes is m4 sprintf.m4 original.c >converted.c If you just want to make the BSD sprintf() look as though it returned an integer, do cat >sprintflen.m4 <<'EOF' define(sprintf,`strlen(`sprintf'($*))')dnl EOF
lgy@pupthy2.PRINCETON.EDU (Larry Yaffe) (05/16/88)
In article <980@cresswell.quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes:
[Using m4 to process macros with variable # arguments]
-I should substantiate that.
-
-If you just want to make the BSD sprintf() look as though it returned an
-integer, do
-
-cat >sprintflen.m4 <<'EOF'
-define(sprintf,`strlen(`sprintf'($*))')dnl
-EOF
This was definitely a helpful suggestion - not being overly familiar
with m4, I hadn't considered using it. However, the suggested m4 scripts
suffer from two small problems:
Whitespace between the "sprintf" and the following argument list must
first be removed in order for m4 to process the arguments correctly.
This is easily accomplished using 'sed'.
Argument lists containing unmatched quoted parentheses, such as,
sprintf (str,"= ("), produce horrible garbage. This is a real occurence
in some of the source I'm dealing with. (However, having to edit a
handful of special sprintf's by hand is a big improvement over having
to edit hundreds.)
------------------------------------------------------------------------
Laurence G. Yaffe Internet: lgy@pupthy.princeton.edu
Department of Physics Bitnet: lgy@pucc
Princeton University UUCP: ...!princeton!pupthy!lgy
PO Box 708, Princeton NJ 08544
gandalf@csli.STANFORD.EDU (Juergen Wagner) (05/17/88)
To put my five cents into this discussion: I prefer to use a simple macro like # ifdef DEBUG # define DBG do_debug # else !DEBUG # define DBG if (0) do_debug # endif DEBUG This will expand the lines of the form DBG(flag, "sorry, the flag is %d", flag); into a line which calls my function do_debug only if DEBUG is set. Of course, do_debug is a function with a variable number of arguments. I know, there are applications where this is not suffifient, and I know one can use double parens, ... This posting is a comment and not a dogma! -- Juergen "Gandalf" Wagner, gandalf@csli.stanford.edu Center for the Study of Language and Information (CSLI), Stanford CA
daveb@llama.rtech.UUCP (It takes a clear mind to make it) (05/17/88)
In article <152@hropus.UUCP> jgy@hropus.UUCP (John Young) writes: >> > Are there any versions of cpp which allow one to define macros which >> > accept variable numbers of arguments? >I think that some of the AT&T CPLU compilers(cpp's) allow this, >you just overdeclare the arguments: > >#define Dprintf(a,b,c,d,e,f,g,h,i) {if (Debug) printf(a,b,c,d,e,f,g,h,i);} > >and compile. You will get a warning about each source line which uses >the wrong number of arguments. If you do #define Dprintf if(Debug) printf you don't get any warnings; you do get possible dangling else problems. This has rarely been a problem on the occasions I've usedthis technique. -dB {amdahl, cpsc6a, mtxinu, sun, hoptoad}!rtech!daveb daveb@rtech.uucp
ed@mtxinu.UUCP (Ed Gould) (05/18/88)
>If you do > >#define Dprintf if(Debug) printf > >you don't get any warnings; you do get possible dangling else problems. To avoid the dangling-else problem, use #define Dprintf if(Debug == 0); else printf for the same effect. -- Ed Gould mt Xinu, 2560 Ninth St., Berkeley, CA 94710 USA {ucbvax,uunet}!mtxinu!ed +1 415 644 0146 "I'll fight them as a woman, not a lady. I'll fight them as an engineer."
dgk@ulysses.homer.nj.att.com (David Korn[eww]) (05/21/88)
Glenn Fowler, author of nmake (4th generation make) has written an ANSI cpp with several nice extensions. One of them is #define foo(a,...) David Korn ulysses!dgk