mcgrath@tully.Berkeley.EDU (Roland McGrath) (10/28/89)
Is this kosher: #include <stddef.h> void foo(char *s, ...) { va_list args; va_start(args, s); bar(va_arg(args, double)); ack(&args); ugh(va_arg(args, int)); va_end(args); } void ack(va_list *args) { blip(va_arg(args, int **)); } I can't tell from the Standard. It works on machines where a `va_list' is a pointer into the stack, but I don't know about other schemes. -- Roland McGrath Free Software Foundation, Inc. roland@ai.mit.edu, uunet!ai.mit.edu!roland
gwyn@smoke.BRL.MIL (Doug Gwyn) (10/28/89)
In article <MCGRATH.89Oct27150426@tully.Berkeley.EDU> mcgrath@tully.Berkeley.EDU (Roland McGrath) writes: >#include <stddef.h> That should be <stdarg.h>, of course. > va_list args; > ack(&args); ... >void ack(va_list *args) >{ > blip(va_arg(args, int **)); >} I wonder how this could possibly have worked. va_arg() takes a va_list as its first argument, not a va_list*. Let's assume this is a typo. I don't have my copy of the Standard at hand at the moment, but I did spend a lot of time working in this area, and as I recall the Standard guarantees that you can pass the va_list to a function and continue to use it within the function, but not necessarily a pointer to the va_list. Upon return from the function, the va_list is "dead" until va_end()ed and re-va_start()ed. To answer the question of whether you can use a pointer to the va_list, you need to consider what types are allowed for va_list. I don't recall exactly how this ended up; it changed around a few times. The one to watch out for is an array type.
mcgrath@paris.Berkeley.EDU (Roland McGrath) (10/29/89)
My example did indeed have typos. What I meant was: #include <stdarg.h> void foo(const char *s, ...) { va_list args; va_start(args, s); bar1(va_arg(args, int)); ack(&args); bar2(va_arg(args, float *)); va_end(args); } void ack(va_list *args) { blip(va_arg(*args, int **)); } I have a somewhat old draft of the Standard (May 1988), but I can't find anything that actually says this isn't allowed. I don't see the problem with whatever type `va_list' is. You can take the address of an object of any type (though not every storage class), and dereference the pointer thus obtained. -- Roland McGrath Free Software Foundation, Inc. roland@ai.mit.edu, uunet!ai.mit.edu!roland
gwyn@smoke.BRL.MIL (Doug Gwyn) (10/30/89)
In article <MCGRATH.89Oct28150927@paris.Berkeley.EDU> mcgrath@paris.Berkeley.EDU (Roland McGrath) writes: >I don't see the problem with whatever type `va_list' is. You can take the >address of an object of any type (though not every storage class), and >dereference the pointer thus obtained. I'm not sure there is a problem, but you need to check carefully what happens when va_list is an array type (which is permitted but not required by the Standard). I'm away from my copy of the Standard now, but for example if va_arg() were permitted to be a function, *args in the inner function would be an attempt to pass an array to va_args(), not just the name of an array (which would be converted to a pointer to the array's first element) as in the top-level function. I forget whether this usage would also result in conversion to a pointer to the first element, but if not then it is illegal (and if it did work, would result in the wrong type being passed to va_args()). I'll have to look this up and let you know. In any case &array will do something different in older PCC implementations than in Standard C (and is officially not allowed according to K&R1), so if the code has to work in both <varargs.h> and <stdarg.h> environments, it may not be portable. I wish I remembered why we allowed (in one draft, even required) the va_list to be an array type. It sure is a nuisance.