#include <stdarg.h>
void bar(va_arg);
void foo(int a, ...)
{
va_list ap;
va_list ap1;
va_start(ap, a);
va_copy(ap1, ap);
va_end(ap);
bar(ap1);
va_end(ap1);
}
Can anyone describe an implementation of stdarg.h such that
a) The above code works.
b) It wouldn't work if one or more of the va_end's were omitted.
c) The implementation of stdarg.h couldn't be trivially changed
so that the va_end's weren't necessary.
?
It seems to me that, if va_end needs to do something that can't
be omitted, then the order of the va_end's must matter.
Since ap and ap1 are auto, the va_start and va_copy can't
depend upon va_end having been called previously. Which leaves
the possibility that va_start and/or va_copy put something
on the stack which must be removed by va_end -- but then
the first va_end would remove the wrong one, yet the standard
doesn't require that they nest.
I have never seen a non-empty va_end. Is there or has there ever
been one? That doesn't break with the above code?
--
<J Q B>
Typically it would deallocate memory that had to
be allocated to hold state variables.
But that's what the va_list is for -- to hold state variables.
Why would *additional* memory be needed? And where would the
memory be allocated from? It can't be on the stack
(or any other global stack), for the reason I noted.
Are there actually implementations that do a malloc()
for every va_start or va_copy and a free for every va_end?
If not, then again -- it seems to me that either there
no non-empty va_ends, or they break the above code.
--
<J Q B>
Some implementations of languages that require stacks on hardware
without a stack use a linked list of dynamically allocated areas
for registers, locals, and temps, e.g. IBM MF: keeps memory usage
down and allows reentrancy.
This is standard IBM MF practice across all OSes, subsystems, and
languages, even assembler, and may not apply to the code
generated for languages supporting only static storage: e.g.
ForTran, COBOL; but the runtime libraries will probably have to
do this.
Exactly when and how much memory is dynamically allocated will
depend on the implementation -- e.g. IBM MF compilers for
different languages from different vendors may have totally
different approaches.
Thanks. Take care, Brian Inglis Calgary, Alberta, Canada
--
Brian....@CSi.com (Brian dot Inglis at SystematicSw dot ab dot ca)
fake address use address above to reply
ab...@aol.com tos...@aol.com ab...@att.com ab...@earthlink.com
ab...@hotmail.com ab...@mci.com ab...@msn.com ab...@sprint.com
ab...@yahoo.com ab...@cadvision.com ab...@shaw.ca ab...@telus.com
ab...@ibsystems.com u...@ftc.gov spam traps
I suggested two alternatives -- 1) that no implementation
needs va_end *or* 2) that implementations of va_end
necessarily break my example, because the standard
doesn't require va_{copy,start}/va_end pairs to nest.
Prior to va_copy, this wasn't an issue, because there
would only be one va_list in a routine, but that's no longer
the case. I'm suggesting that the standard may need to
require that they nest.
--
<J Q B>
Such a linked list implements a stack. As I noted,
"It can't be on the stack (or any other global stack) ..."
^^^^^^^^^^^^^^^^^^^^^^^^^
The point is that the standard does not require
va_{start,copy}/va_end to nest; therefore va_{start,copy} cannot
allocate memory on any sort of stack, whether a contiguous area
addressed by a stack pointer, or a linked list of frames,
and have va_end to deallocate that memory, given the current
wording of the standard. Or so it seems to me, and I don't
believe anyone has given any reason to think otherwise.
> This is standard IBM MF practice across all OSes, subsystems, and
> languages, even assembler, and may not apply to the code
> generated for languages supporting only static storage: e.g.
> ForTran, COBOL; but the runtime libraries will probably have to
> do this.
> Exactly when and how much memory is dynamically allocated will
> depend on the implementation -- e.g. IBM MF compilers for
> different languages from different vendors may have totally
> different approaches.
>
> Thanks. Take care, Brian Inglis Calgary, Alberta, Canada
--
<J Q B>
In article <3E0BAAA7...@cW.comdiespammersdie>, Jim Balter
<Jim.B...@cW.comdiespammersdie> writes
>I suggested two alternatives -- 1) that no implementation
>needs va_end *or* 2) that implementations of va_end
>necessarily break my example, because the standard
>doesn't require va_{copy,start}/va_end pairs to nest.
>Prior to va_copy, this wasn't an issue, because there
>would only be one va_list in a routine,
What gives you that idea? There is nothing to prevent a function having
more than one va_list at the same time.
Slightly contrived example: a function that compares two null-terminated
lists of strings:
int comp_str_lists (char *s1, ...)
{
int result = 0;
va_list list1, list2;
va_start (list1, s1);
va_start (list2, s2);
while (va_arg (list2, char *) != NULL)
;
char *s2 = va_arg (list2, char *);
while (s1 != NULL && s2 != NULL)
{
int r = strcmp (s1, s2);
if (r != 0) break;
s1 = va_arg (list1, char *);
s2 = va_arg (list2, char *);
}
va_end (list1);
va_end (list2);
return r != 0 ? r :
s1 != NULL ? +1 :
s2 != NULL ? -1 : 0;
}
// ...
comp_str_lists ("-a", "test", NULL, argv [1], argv [2], NULL);
>I'm suggesting that the standard may need to
>require that they nest.
But why? That just breaks existing usage.
--
Clive D.W. Feather, writing for himself | Home: <cl...@davros.org>
Tel: +44 20 8371 1138 (work) | Web: <http://www.davros.org>
Fax: +44 870 051 9937 | Work: <cl...@demon.net>
Written on my laptop; please observe the Reply-To address
Shouldn't that be:
va_start(list2, s1);
Yes.
[Exits, muttering.]