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

Initializing va_list in function without ellipsis

2,010 views
Skip to first unread message

Bjorn Reese

unread,
Aug 29, 2002, 9:11:46 AM8/29/02
to
How can a va_list be properly initialized in a function which does
not have ellipsis in its signature?

Consider the following contrived function, which takes parameters
either as a va_list or as an array of pointers.

void f(int use_va, va_list va_param, void **ptr_param) {
if (use_va) {
/* Use va_param */
} else {
/* Use ptr_param */
}
}

This is used by the following two functions. The first poses no problem,
but in the second I cannot initialize the dummy variable in a portable
way.

void use_f_with_va(const char *format, ...) {
va_list parameters;
va_start(parameters, format);
f(TRUE, parameters, NULL);
va_end(parameters);
}

void use_f_with_ptr(const char *format, void **ptr) {
va_list dummy;
/* How is dummy initialized? */
f(FALSE, dummy, ptr);
}

According to my reading of C99, the only proper way to initialize a va_list
is with va_start. However, many compilers refuse to compile this because
the function signature does not contain ellipsis.

Barry Margolin

unread,
Aug 29, 2002, 11:09:39 AM8/29/02
to
In article <3D6E1D92...@mail1.stofanet.dk>,

Bjorn Reese <bre...@mail1.stofanet.dk> wrote:
>How can a va_list be properly initialized in a function which does
>not have ellipsis in its signature?
>
>Consider the following contrived function, which takes parameters
>either as a va_list or as an array of pointers.
>
> void f(int use_va, va_list va_param, void **ptr_param) {
> if (use_va) {
> /* Use va_param */
> } else {
> /* Use ptr_param */
> }
> }

If the language doesn't provide a valid way to use a function like this, it
seems like a very bad design decision to create such an interface. Why not
have separate functions, f_va() and f_array()?

> void use_f_with_ptr(const char *format, void **ptr) {
> va_list dummy;
> /* How is dummy initialized? */
> f(FALSE, dummy, ptr);
> }
>
>According to my reading of C99, the only proper way to initialize a va_list
>is with va_start. However, many compilers refuse to compile this because
>the function signature does not contain ellipsis.

Maybe:

f(FALSE, (va_list)0, ptr);

But this probably invokes UB.

--
Barry Margolin, bar...@genuity.net
Genuity, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.

Ian Pilcher

unread,
Aug 29, 2002, 2:57:44 PM8/29/02
to
Bjorn Reese wrote:
> How can a va_list be properly initialized in a function which does
> not have ellipsis in its signature?
>
> Consider the following contrived function, which takes parameters
> either as a va_list or as an array of pointers.
>
> void f(int use_va, va_list va_param, void **ptr_param) {
> if (use_va) {
> /* Use va_param */
> } else {
> /* Use ptr_param */
> }
> }
>

My suggestion is to change this to:

void f(int use_va, va_list *p_va_param, void **ptr_param) {
if (use_va) {
/* Use *p_va_param */


} else {
/* Use ptr_param */
}
}

> This is used by the following two functions. The first poses no problem,
> but in the second I cannot initialize the dummy variable in a portable
> way.
>
> void use_f_with_va(const char *format, ...) {
> va_list parameters;
> va_start(parameters, format);
> f(TRUE, parameters, NULL);
> va_end(parameters);
> }

This would become:

void use_f_with_va(const char *format, ...) {

va_list_parameters;
va_start(parameters, format);
f(TRUE, &parameters, NULL);
va_end(parameters);
}

>
> void use_f_with_ptr(const char *format, void **ptr) {
> va_list dummy;
> /* How is dummy initialized? */
> f(FALSE, dummy, ptr);
> }

And:

void use_f_with_ptr(const char *format, void **ptr) {

f(FALSE, NULL, ptr);


}
>
> According to my reading of C99, the only proper way to initialize a va_list
> is with va_start. However, many compilers refuse to compile this because
> the function signature does not contain ellipsis.

C99 specifically allows using pointers to va_lists.

OTOH, this seems like an awfully convoluted interface. If your really
want to do function overloading, use C++.
--
========================================================================
Ian Pilcher pilc...@attbi.com
========================================================================

Bjorn Reese

unread,
Aug 29, 2002, 6:11:22 PM8/29/02
to
Ian Pilcher wrote:

> My suggestion is to change this to:
>
> void f(int use_va, va_list *p_va_param, void **ptr_param) {

Thanks. That seems to work very well (I still need to check on some
further platforms though.)

Bjorn Reese

unread,
Aug 29, 2002, 6:10:47 PM8/29/02
to
Barry Margolin wrote:

> If the language doesn't provide a valid way to use a function like this, it
> seems like a very bad design decision to create such an interface. Why not
> have separate functions, f_va() and f_array()?

Well, the example was contrived. It may become more apparent why I
cannot have two separate functions, if I describe the actual use.

The actual code is a printf implementation [1], which supports both
the normal va_list parameter used by the vprintf functions, and
indirectly by the printf functions, as well as a pointer array used
by the non-standard printfv functions.

All these share the same format string parser [2], and this parser
is the one that needs the odd interface.

If you have any suggestions about how I can re-design it, without
duplicating the parser code (which is about 1000 LOC), then I am
all ears. Btw, my concern with code duplication is not size, but
rather inconsistancy between the two instances.

> f(FALSE, (va_list)0, ptr);

Doesn't work on platforms where va_list is implemented as a struct.

[1] http://ctrio.sourceforge.net/
[2] The TrioParse() function in the trio.c file of [1]

David Hopwood

unread,
Aug 29, 2002, 8:41:56 PM8/29/02
to
-----BEGIN PGP SIGNED MESSAGE-----

Bjorn Reese wrote:
> How can a va_list be properly initialized in a function which does
> not have ellipsis in its signature?
>
> Consider the following contrived function, which takes parameters
> either as a va_list or as an array of pointers.

[...]


> This is used by the following two functions. The first poses no problem,
> but in the second I cannot initialize the dummy variable in a portable
> way.
>
> void use_f_with_va(const char *format, ...) {
> va_list parameters;
> va_start(parameters, format);
> f(TRUE, parameters, NULL);
> va_end(parameters);
> }
>
> void use_f_with_ptr(const char *format, void **ptr) {
> va_list dummy;
> /* How is dummy initialized? */
> f(FALSE, dummy, ptr);
> }
>
> According to my reading of C99, the only proper way to initialize a va_list
> is with va_start. However, many compilers refuse to compile this because
> the function signature does not contain ellipsis.

void use_f_with_ptr(const char *format, void **ptr) {

workaround(format, ptr);
}

void workaround(const char *format, void **ptr, ...) {
va_list dummy;
va_start(dummy, ptr);
f(FALSE, dummy, ptr);
va_end(dummy);
}

"Any problem in computer science can be solved with another layer of
indirection." -- David Wheeler

- --
David Hopwood <david....@zetnet.co.uk>

Home page & PGP public key: http://www.users.zetnet.co.uk/hopwood/
RSA 2048-bit; fingerprint 71 8E A6 23 0E D3 4C E5 0F 69 8C D4 FA 66 15 01
Nothing in this message is intended to be legally binding. If I revoke a
public key but refuse to specify why, it is because the private key has been
seized under the Regulation of Investigatory Powers Act; see www.fipr.org/rip


-----BEGIN PGP SIGNATURE-----
Version: 2.6.3i
Charset: noconv

iQEVAwUBPW6/LjkCAxeYt5gVAQHgSAgApm7fZlmpmGofSnY0VhywZ5bJ+Gu6F6hw
KZcppjINEdN7ZIRX14Bpe7EOtsfjlwSJYr0g4Iyll2uwAYeRdRU25K4tiimAumRo
tmV6AGBUOqGiyke3FTW7RKjoq5YM67BFJMU6ujqWLJpSP3wMX+k9wPZVWuSOMfUY
FnK7fiJMnQbWtwA57TwlRTvY3MIKD0bnjUQNbu6cO+bjcbLbi1ExvinZtNUzd0vb
uSmsOS3Lv8kP4CsWA/KsJvJ8JiKiwvKd0rAMszmQ8Aj11bNahwYISIqTFLHN6USo
3SHRyMvJm+P5OS232oAbV0Y+ZVN1dCu/HVoj+LyUgiEn2Z4szKHhJg==
=Cb/a
-----END PGP SIGNATURE-----

Douglas A. Gwyn

unread,
Aug 29, 2002, 8:08:51 PM8/29/02
to
Bjorn Reese wrote:
> The actual code is a printf implementation [1], which supports both
> the normal va_list parameter used by the vprintf functions, and
> indirectly by the printf functions, as well as a pointer array used
> by the non-standard printfv functions.
> All these share the same format string parser [2], and this parser
> is the one that needs the odd interface.

int printf(const char *format, ...) {
va_list ap;
int status;
va_start(ap, format);
status = vprintf(format, ap);
va_end(ap);
return status;
}

int vprintf(const char *format, va_list ap) {
return pf_parse(format, ap, (void**)NULL);
}


int printfv(const char *format, void *args[]) {
va_list dummy;
return pf_parse(format, dummy, args);
}

int pf_parse(const char *format, va_list ap, void *args[]) {
...
whatever = args == NULL ? va_arg(ap, sometype)
: *(sometype *)args[i];
...
}

Zack Weinberg

unread,
Aug 29, 2002, 9:03:40 PM8/29/02
to
Bjorn Reese <bre...@mail1.stofanet.dk> writes:
>
>If you have any suggestions about how I can re-design it, without
>duplicating the parser code (which is about 1000 LOC), then I am
>all ears. Btw, my concern with code duplication is not size, but
>rather inconsistancy between the two instances.

Have the variable-argument-taking routine scan the argument list
and construct a temporary array from the variable arguments, which
you then pass to the array-taking routine, which does all the real
work.

You have to do this anyway if you want to implement numbered argument
notation (%1$s).

zw

Bjorn Reese

unread,
Aug 30, 2002, 6:55:11 AM8/30/02
to
"Douglas A. Gwyn" wrote:

> int printfv(const char *format, void *args[]) {
> va_list dummy;
> return pf_parse(format, dummy, args);
> }

Your suggestion is exactly what I am doing already. The problem is
that most compilers complain about the dummy variable above being
uninitialized.

I am perfectly aware that this is only a compiler warning, which
does not prevent the compilation of the software. However, this
is the most frequent "bug" report I receive, so I am trying to
find a portable way to avoid the warnings.

I apologize for not explaining the above from the beginning, but
at first I was merely looking for a way to initialize the va_list
to prevent the compiler warnings. However, Ian Pilcher's suggestion
to use pointers to va_list seems like a better solution.

Wojtek Lerch

unread,
Aug 30, 2002, 10:14:52 AM8/30/02
to
"Douglas A. Gwyn" <DAG...@null.net> wrote in message news:<3D6EB793...@null.net>...

> int printfv(const char *format, void *args[]) {
> va_list dummy;
> return pf_parse(format, dummy, args);
> }

There's no guarantee that the type va_list doesn't have trap
representations, is there?

Barry Margolin

unread,
Aug 30, 2002, 10:20:40 AM8/30/02
to
In article <akmg9c$249$1...@panix3.panix.com>,

Zack Weinberg <za...@panix.com> wrote:
>Bjorn Reese <bre...@mail1.stofanet.dk> writes:
>>
>>If you have any suggestions about how I can re-design it, without
>>duplicating the parser code (which is about 1000 LOC), then I am
>>all ears. Btw, my concern with code duplication is not size, but
>>rather inconsistancy between the two instances.
>
>Have the variable-argument-taking routine scan the argument list
>and construct a temporary array from the variable arguments, which
>you then pass to the array-taking routine, which does all the real
>work.

But in order to determine how many arguments there are it would have to
parse the format string, and this is presumably implemented in the common
routine that he wants to call. This is the code he's trying to avoid
duplicating.

Douglas A. Gwyn

unread,
Aug 30, 2002, 5:42:57 PM8/30/02
to
Bjorn Reese wrote:
> "Douglas A. Gwyn" wrote:
> > int printfv(const char *format, void *args[]) {
> > va_list dummy;
> > return pf_parse(format, dummy, args);
> > }
> Your suggestion is exactly what I am doing already. The problem is
> that most compilers complain about the dummy variable above being
> uninitialized.

I should have written
static va_list dummy;

That is, according to the language definition, default-initialized.

Kai Henningsen

unread,
Sep 1, 2002, 12:29:00 PM9/1/02
to
bre...@mail1.stofanet.dk (Bjorn Reese) wrote on 29.08.02 in <3D6E9BE7...@mail1.stofanet.dk>:

> The actual code is a printf implementation [1], which supports both
> the normal va_list parameter used by the vprintf functions, and
> indirectly by the printf functions, as well as a pointer array used
> by the non-standard printfv functions.
>
> All these share the same format string parser [2], and this parser
> is the one that needs the odd interface.

It's not all that hard, but it's weird:

int internal_formatter(int is_v, char *format, va_list ap)
{
void **plist;
if (is_v)
plist = va_arg(ap, void **);
/* ... */
}

int internal_printfv(char *format, ...)
{
va_list ap;
va_start(ap, format);
return internal_formatter(1, format, ap);
}

int printfv(char *format, void *args[])
{
return internal_printfv(format, args);
}

That is, you have an intermediate variable argument function which does
nothing but encapsulate your array into a va_list so you have a va_list to
pass.

Kai
--
http://www.westfalen.de/private/khms/
"... by God I *KNOW* what this network is for, and you can't have it."
- Russ Allbery (r...@stanford.edu)

Al Grant

unread,
Sep 2, 2002, 3:25:58 AM9/2/02
to
"Douglas A. Gwyn" <DAG...@null.net> wrote in message news:<3D6FE6E1...@null.net>...

Can you be sure that the default for a va_list is not a
trap representation?

Douglas A. Gwyn

unread,
Sep 3, 2002, 12:53:49 AM9/3/02
to
Al Grant wrote:
> Can you be sure that the default for a va_list is not a
> trap representation?

Yes.

Al Grant

unread,
Sep 3, 2002, 2:41:31 PM9/3/02
to
"Douglas A. Gwyn" <DAG...@null.net> wrote in message news:<3D7440DB...@null.net>...

How? What if va_list is not a scalar, aggregate or union type,
but some implementation-originated type to which the default
initialization rules do not apply?

Douglas A. Gwyn

unread,
Sep 4, 2002, 9:50:56 PM9/4/02
to
Al Grant wrote:
> How? What if va_list is not a scalar, aggregate or union type,
> but some implementation-originated type to which the default
> initialization rules do not apply?

It won't be, in a conforming implementation.

0 new messages