kenc@madmax.Viewlogic.COM (Kenstir) (11/03/90)
Can you argument lists two levels down? I passed an argument list to a function, took a couple of parameters off, then tried to pass the rest of the argument list down to another function. At this point, the parameters are no good. Yet, it seems to work with vprintf and the like. Some code follows (sorry, this is as short as I could get it). Why do the first three calls to getMsg() work, while the calls to err() fail? Thanks! /**************************************************************************/ #include <stdio.h> #include <varargs.h> #define SIZE 512 char *msg_array[] = { "This is message #1, int=%d, string=%s", "msg two, only a float=%f", "third one, string=%s, int=%d, long=%ld", }; static char message[SIZE]; /**************************************************************************/ char *getMsg (va_alist) va_dcl /* msg_id, ... */ { va_list args; int msg_id; va_start (args); msg_id = va_arg (args, int); vsprintf (message, msg_array[msg_id], args); va_end (args); return (message); } /**************************************************************************/ void err(va_alist) va_dcl /* app, msg_num, ... */ { va_list args; char *cp, *ret, *app; int num; va_start (args); app = va_arg (args, char *); num = va_arg (args, int); ret = getMsg (num, args); va_end (args); printf ("%s: %s\n", app, ret); } /**************************************************************************/ main () { printf ("%s\n", getMsg(0, 37, "this is the string")); printf ("%s\n", getMsg(1, 37.37)); printf ("%s\n", getMsg(2, "foo", 37, 37L)); err ("app1", 0, 37, "this is the string"); err ("app2", 1, 37.37); err ("app3", 2, "foo", 37, 37L); } /**************************************************************************/ p.s. Anyone got any varargs macros, portable between traditional varargs and ANSI stdarg? Wanna share them? p.p.s. Thanks for helping! -- Kenneth H. Cox Viewlogic Systems, Inc. kenstir@viewlogic.com ...!harvard!cg-atla!viewlog!kenstir
chris@mimsy.umd.edu (Chris Torek) (11/04/90)
In article <1990Nov2.170614@madmax.Viewlogic.COM> kenc@madmax.Viewlogic.COM (Kenstir) writes: >I passed [a variable] argument list to a function, took a couple of >parameters off, then tried to pass the rest of the argument list down >to another function. ... This can be done, but not the way you think. getMsg is correct: [Apologies for the long quotes; I have squished them vertically. I do not recommend coding in this style.] >char *getMsg(va_alist) va_dcl { va_list args; int msg_id; > va_start(args); msg_id = va_arg(args, int); > vsprintf(message, msg_array[msg_id], args); > va_end(args); > return (message); >} Note well the fact that getMsg (which is correct and works) must (and does) call vsprintf, not sprintf. That `v' is important. The next function, however, is wrong: >void err(va_alist) va_dcl { va_list args; char *cp, *ret, *app; int num; > va_start(args); app = va_arg(args, char *); > num = va_arg(args, int); > ret = getMsg(num, args); Here is the erroneous line. How do you expect getMsg to work when you had to call vsprintf? If getMsg was good enough to do the trick, why would vsprintf exist at all? The fix, then, is to write a `vgetMsg' function. In the process it is simplest to rewrite getMsg in terms of vgetMsg: vgetMsg(msg_id, ap) int msg_id; va_list ap; { (void) vsprintf(message, msg_array[msg_id], args); return (message); } getMsg(va_alist) va_dcl { va_list args; int msg_id; char *ret; va_start(args); msg_id = va_arg(args, int); ret = vgetMsg(msg_id, args); va_end(args); return (ret); } Now change the last quoted line of `err' to ret = vgetMsg(num, args); >p.s. Anyone got any varargs macros, portable between > traditional varargs and ANSI stdarg? If you mean what I think you mean, it cannot be done. The reason is that `va_start' has the same name in <varargs.h> and <stdarg.h> but the former version (used above) has only one parameter while the latter has two. It is thus impossible to write a single implementation. If you mean the other thing I think you mean, it can be done, but it looks horrible (and I will not even give an example). -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 405 2750) Domain: chris@cs.umd.edu Path: uunet!mimsy!chris
lerman@stpstn.UUCP (Ken Lerman) (11/06/90)
In article <27416@mimsy.umd.edu> chris@mimsy.umd.edu (Chris Torek) writes:
...
[->> has lost attribution.]
->>p.s. Anyone got any varargs macros, portable between
->> traditional varargs and ANSI stdarg?
->
->If you mean what I think you mean, it cannot be done. The reason
->is that `va_start' has the same name in <varargs.h> and <stdarg.h>
->but the former version (used above) has only one parameter while the
->latter has two. It is thus impossible to write a single implementation.
->
->If you mean the other thing I think you mean, it can be done, but it
->looks horrible (and I will not even give an example).
->--
->In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 405 2750)
->Domain: chris@cs.umd.edu Path: uunet!mimsy!chris
I generally put the following in my code (by #include):
#if defined(__STDC__) && __STDC__ != 0
#include <stdarg.h>
#define VA_START(ap,last) va_start(ap,last)
#else
#include <varargs.h>
#define VA_START(ap,last) va_start(ap)
#endif
Then I can write VA_START(ap, lastArg) in my code as if I'm using the
ANSI style of va_start.
While this is not a single va_start which does both, I think it meets
the portablility goals which were stated.
Ken