Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

va_end

39 views
Skip to first unread message

Jim Balter

unread,
Dec 22, 2002, 2:49:56 AM12/22/02
to
Given

#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>

Douglas A. Gwyn

unread,
Dec 22, 2002, 10:45:11 AM12/22/02
to
Jim Balter wrote:
> I have never seen a non-empty va_end.

Typically it would deallocate memory that had to
be allocated to hold state variables.

Jim Balter

unread,
Dec 22, 2002, 11:41:37 PM12/22/02
to

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>

Douglas A. Gwyn

unread,
Dec 23, 2002, 2:56:13 PM12/23/02
to
I'd have to resurrect my notes from long ago, where I
was the "point of contact" for varargs during the
process leading to the C89 standard. In fact several
compiler implementors using a variety of platforms,
some of them rather unusual, provided input on this
issue, leading us to conclude that va_end sometimes
was needed. Note that this was assumed even by the
designers of the historical de facto <varargs.h>
interface, although one often encountered code that
omitted the va_end (probably because the programmers
knew too much about the specific implementation on
the platforms they happened to be using at the time).
I don't think it's important enough to revisit now.

Brian Inglis

unread,
Dec 24, 2002, 12:25:12 PM12/24/02
to

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

Jim Balter

unread,
Dec 26, 2002, 8:19:34 PM12/26/02
to

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>

Jim Balter

unread,
Dec 26, 2002, 9:01:41 PM12/26/02
to
On 12/24/02 9:25 AM, Brian Inglis wrote:
> On Mon, 23 Dec 2002 04:41:37 GMT, Jim Balter
> <Jim.B...@cW.comdiespammersdie> wrote:
>
>
>>On 12/22/02 7:45 AM, Douglas A. Gwyn wrote:
>>
>>>Jim Balter wrote:
>>>
>>>
>>>>I have never seen a non-empty va_end.
>>>
>>>
>>>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.
>
>
> 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.

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>

Clive D. W. Feather

unread,
Feb 19, 2003, 1:36:29 PM2/19/03
to
[Old thread, but so what?]

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

James Kuyper

unread,
Feb 19, 2003, 3:35:30 PM2/19/03
to
"Clive D. W. Feather" wrote:
...

> int comp_str_lists (char *s1, ...)
> {
> int result = 0;
> va_list list1, list2;
> va_start (list1, s1);
> va_start (list2, s2);

Shouldn't that be:
va_start(list2, s1);

Clive D. W. Feather

unread,
Feb 20, 2003, 1:46:49 PM2/20/03
to
In article <3E53EA92...@saicmodis.com>, James Kuyper
<kuy...@saicmodis.com> writes

>> va_start (list2, s2);
>Shouldn't that be:
> va_start(list2, s1);

Yes.

[Exits, muttering.]

0 new messages