473,320 Members | 1,823 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

va_arg()

LIT
Hello,

I have a question about va_arg() usage :
Is there any way how I can check or ensure at compile time that
va_arg() is not called when there are
no next arguments anymore.
I understood that calling va_arg() when there are no next arguments
causes an undefined behaviour.

Thanks

Oct 26 '06 #1
16 4797
In article <11**********************@k70g2000cwa.googlegroups .com>,
LIT <to************@dana.comwrote:
>Is there any way how I can check or ensure at compile time that
va_arg() is not called when there are
no next arguments anymore.
No, your program has to work that out for itself. Typically one
of the arguments indicates how many other arguments there are (as
in printf()) or a special value (such as 0) is used as an extra
terminating argument.

-- Richard
Oct 26 '06 #2

LIT wrote:
I have a question about va_arg() usage :
Is there any way how I can check or ensure at compile time that
va_arg() is not called when there are
no next arguments anymore.
No - it is essential that you have a means (usually based on your first
argument) to determine how many times to invoke va_arg().

See (for example)
http://docs.mandragor.org/files/Prog...C-faq/s15.html
and
http://docs.mandragor.org/files/Prog...faq/q15.8.html
I understood that calling va_arg() when there are no next arguments
causes an undefined behaviour.
Yep. (My manual page talks of "random errors" :-)

Oct 26 '06 #3
LIT

ma**********@pobox.com schreef:
LIT wrote:
I have a question about va_arg() usage :
Is there any way how I can check or ensure at compile time that
va_arg() is not called when there are
no next arguments anymore.

No - it is essential that you have a means (usually based on your first
argument) to determine how many times to invoke va_arg().

See (for example)
http://docs.mandragor.org/files/Prog...C-faq/s15.html
and
http://docs.mandragor.org/files/Prog...faq/q15.8.html
I understood that calling va_arg() when there are no next arguments
causes an undefined behaviour.

Yep. (My manual page talks of "random errors" :-)
I understand
Nevertheless, if I have a function like this :

foo(unsigned char Nvars, ...)
{
unsigned int i;
unsigned int test[10];
va_list tag ;
va_start(tag,Nvars);
for (i=0 ; i<Nvars ; i++)
{
test[i] = va_arg(tag, unsigned int);
}
va_end(tag)
}

and I do this (eg. accidentally, during coding) :

foo(4, x, y) ; (x and y are unsigned int params),

then there is no clear means to detect this at compile time

Oct 26 '06 #4

LIT wrote:
ma**********@pobox.com schreef:
LIT wrote:
I have a question about va_arg() usage :
Is there any way how I can check or ensure at compile time that
va_arg() is not called when there are
no next arguments anymore.
No - it is essential that you have a means (usually based on your first
argument) to determine how many times to invoke va_arg().

See (for example)
http://docs.mandragor.org/files/Prog...C-faq/s15.html
and
http://docs.mandragor.org/files/Prog...faq/q15.8.html
I understood that calling va_arg() when there are no next arguments
causes an undefined behaviour.
Yep. (My manual page talks of "random errors" :-)

I understand
Nevertheless, if I have a function like this :

foo(unsigned char Nvars, ...)
{
unsigned int i;
unsigned int test[10];
va_list tag ;
va_start(tag,Nvars);
for (i=0 ; i<Nvars ; i++)
{
test[i] = va_arg(tag, unsigned int);
}
va_end(tag)
}

and I do this (eg. accidentally, during coding) :

foo(4, x, y) ; (x and y are unsigned int params),

then there is no clear means to detect this at compile time
When we had this issue, I wrote a perl script that scanned our source
files to ensure that all calls to a predefined set of varargs functions
had a NULL as the last argument, that being what we used as a sentinel.
It wasn't perfect, but it was helpful. You might be able to come up
with a similar tool that meets your needs.

-David

Oct 26 '06 #5

LIT wrote:
if I have a function like this :

foo(unsigned char Nvars, ...)
and I do this (eg. accidentally, during coding) :

foo(4, x, y) ; (x and y are unsigned int params),

then there is no clear means to detect this at compile time
That's true - because the compiler doesn't know (and the language
provides no means of defining) that the first parameter to foo() has
any specific meaning.

The foo() implementation and the foo() invocation are independently
parsed and compiled (they could be in separate source files, you just
happened to combine declaring and defining foo() in your example).

Oct 26 '06 #6
LIT wrote:
ma**********@pobox.com schreef:

>>LIT wrote:

>>>I have a question about va_arg() usage :
Is there any way how I can check or ensure at compile time that
va_arg() is not called when there are
no next arguments anymore.

No - it is essential that you have a means (usually based on your first
argument) to determine how many times to invoke va_arg().

See (for example)
http://docs.mandragor.org/files/Prog...C-faq/s15.html
and
http://docs.mandragor.org/files/Prog...faq/q15.8.html

>>>I understood that calling va_arg() when there are no next arguments
causes an undefined behaviour.

Yep. (My manual page talks of "random errors" :-)


I understand
Nevertheless, if I have a function like this :

foo(unsigned char Nvars, ...)
{
unsigned int i;
unsigned int test[10];
va_list tag ;
va_start(tag,Nvars);
for (i=0 ; i<Nvars ; i++)
{
test[i] = va_arg(tag, unsigned int);
}
va_end(tag)
}

and I do this (eg. accidentally, during coding) :

foo(4, x, y) ; (x and y are unsigned int params),

then there is no clear means to detect this at compile time
You can compute the number of arguments automatically by writing a macro
with the same name and use the macro PP_NARG I posted on comp.std.c some
time ago
(http://groups.google.com.au/group/co...e4a3fb?hl=en):

extern void foo(int n, ...);

#define foo(...) foo(PP_NARG(__VA_ARGS__)-1, __VA_ARGS__)

foo(x,y) -foo(2,x,y)

The case:

foo() -foo(0)

is a bit more complex but possible.

a+, ld.
Oct 26 '06 #7
On 26 Oct 2006, "LIT" <to************@dana.comwrote:
Nevertheless, if I have a function like this :

foo(unsigned char Nvars, ...)
{
unsigned int i;
unsigned int test[10];
va_list tag ;
va_start(tag,Nvars);
for (i=0 ; i<Nvars ; i++)
{
test[i] = va_arg(tag, unsigned int);
}
va_end(tag)
}

and I do this (eg. accidentally, during coding) :

foo(4, x, y) ; (x and y are unsigned int params),

then there is no clear means to detect this at compile time
I'd love to hear about a clean, portable solution to this, but I don't
know of one. In the case you give, where the first argument is the
number of varargs, you could use a macro to help a little:

#define FOO_ARGS_1(a) 1, (a)
#define FOO_ARGS_2(a,b) 2, (a), (b)

etc. I'm not claiming it's pretty, but you should at least get a
compiler warning if you invoke one of the macros with the wrong number
of arguments.

Dave

--
D.a.v.i.d T.i.k.t.i.n
t.i.k.t.i.n [at] a.d.v.a.n.c.e.d.r.e.l.a.y [dot] c.o.m
Oct 26 '06 #8


LIT wrote On 10/26/06 11:23,:
[...]
Nevertheless, if I have a function like this :

foo(unsigned char Nvars, ...)
{
unsigned int i;
unsigned int test[10];
va_list tag ;
va_start(tag,Nvars);
for (i=0 ; i<Nvars ; i++)
{
test[i] = va_arg(tag, unsigned int);
}
va_end(tag)
}

and I do this (eg. accidentally, during coding) :

foo(4, x, y) ; (x and y are unsigned int params),

then there is no clear means to detect this at compile time
Right, because the compiler doesn't know how you are going
to figure out the number and types of the optional arguments.
The scheme you use could be arbitrarily complicated: Maybe the
number of optional arguments is the square root of the first
argument, or maybe foo() stops looking for optional arguments
once their running sum exceeds the value of the first one, or
maybe the first argument is actually a bunch of bit-fields that
encode descriptions of the optional arguments, or ...

Some compilers have been "taught" the rules for variable-
argument library functions (Standard and otherwise), and can
do at least a partial validity check at compile time. At least
one compiler provides a way for you, the programmer, to state
that your print_in_colors() function is "printf-like" and can
be checked similarly. But I haven't heard of a compiler that
allows you to add new checking rules of your own.

By the way: Elsethread, someone mentioned using NULL as
a sentinel to mark the end of the list of optional arguments.
Thought question: Why is this a bad idea, and how could it
be made better? (Hint: What is the type of the expression
the NULL macro expands to?)

--
Er*********@sun.com

Oct 26 '06 #9
Eric Sosman <Er*********@sun.comwrote:
By the way: Elsethread, someone mentioned using NULL as
a sentinel to mark the end of the list of optional arguments.
Thought question: Why is this a bad idea, and how could it
be made better? (Hint: What is the type of the expression
the NULL macro expands to?)
I assume you're talking about the general case - obviously NULL as a
sentinel could not work for a function such as printf() where the
type of each argument varies. I fail to see how using a sentinel
value to terminate a list of arguments *of the same type* is a bad
idea and I assume that's not what you were getting at.

--
C. Benson Manica | I *should* know what I'm talking about - if I
cbmanica(at)gmail.com | don't, I need to know. Flames welcome.
Oct 26 '06 #10
Christopher Benson-Manica wrote:
Eric Sosman <Er*********@sun.comwrote:
By the way: Elsethread, someone mentioned using NULL as
a sentinel to mark the end of the list of optional arguments.
Thought question: Why is this a bad idea, and how could it
be made better? (Hint: What is the type of the expression
the NULL macro expands to?)

I assume you're talking about the general case - obviously NULL as a
sentinel could not work for a function such as printf() where the
type of each argument varies. I fail to see how using a sentinel
value to terminate a list of arguments *of the same type* is a bad
idea and I assume that's not what you were getting at.
I think his point is that you need to cast NULL to void* when passing
to a varargs function because it may be just a naked 0 and int may be
smaller than void*. I didn't make up the code in question, it
preceeded me. But fixing it (with a cast or some other approach)
doesn't seem worthwhile to me as it is unlikely to break any time soon.

-David

Oct 26 '06 #11
Christopher Benson-Manica <at***@norge.freeshell.orgwrites:
Eric Sosman <Er*********@sun.comwrote:
> By the way: Elsethread, someone mentioned using NULL as
a sentinel to mark the end of the list of optional arguments.
Thought question: Why is this a bad idea, and how could it
be made better? (Hint: What is the type of the expression
the NULL macro expands to?)

I assume you're talking about the general case - obviously NULL as a
sentinel could not work for a function such as printf() where the
type of each argument varies. I fail to see how using a sentinel
value to terminate a list of arguments *of the same type* is a bad
idea and I assume that's not what you were getting at.
The point is that we don't *know* the type of the expression the NULL
macro expands to; it could be either int or void* (there are other
possibilities).

"(void*)NULL" is a better sentinel value.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Oct 26 '06 #12
"David Resnick" <ln********@gmail.comwrites:
Christopher Benson-Manica wrote:
>Eric Sosman <Er*********@sun.comwrote:
By the way: Elsethread, someone mentioned using NULL as
a sentinel to mark the end of the list of optional arguments.
Thought question: Why is this a bad idea, and how could it
be made better? (Hint: What is the type of the expression
the NULL macro expands to?)

I assume you're talking about the general case - obviously NULL as a
sentinel could not work for a function such as printf() where the
type of each argument varies. I fail to see how using a sentinel
value to terminate a list of arguments *of the same type* is a bad
idea and I assume that's not what you were getting at.

I think his point is that you need to cast NULL to void* when passing
to a varargs function because it may be just a naked 0 and int may be
smaller than void*. I didn't make up the code in question, it
preceeded me. But fixing it (with a cast or some other approach)
doesn't seem worthwhile to me as it is unlikely to break any time soon.
What do you mean by "any time soon"? It could break the moment you
recompile it on a 64-bit platform.

You don't actually have to wait for the code to fail before you fix
it.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Oct 26 '06 #13


Keith Thompson wrote On 10/26/06 14:55,:
Christopher Benson-Manica <at***@norge.freeshell.orgwrites:
>>Eric Sosman <Er*********@sun.comwrote:
>> By the way: Elsethread, someone mentioned using NULL as
a sentinel to mark the end of the list of optional arguments.
Thought question: Why is this a bad idea, and how could it
be made better? (Hint: What is the type of the expression
the NULL macro expands to?)

I assume you're talking about the general case - obviously NULL as a
sentinel could not work for a function such as printf() where the
type of each argument varies. I fail to see how using a sentinel
value to terminate a list of arguments *of the same type* is a bad
idea and I assume that's not what you were getting at.


The point is that we don't *know* the type of the expression the NULL
macro expands to; it could be either int or void* (there are other
possibilities).

"(void*)NULL" is a better sentinel value.
Right. Or (char*)NULL, or (struct thing*)NULL, or
whatever pointer type the function expects to retrieve
with va_arg(). The point I wanted to make is that a
"bare" NULL makes an unreliable sentinel, because its
type is implementation-defined and quite likely wrong
for the purpose.

--
Er*********@sun.com

Oct 26 '06 #14

Keith Thompson wrote:
"David Resnick" <ln********@gmail.comwrites:
Christopher Benson-Manica wrote:
Eric Sosman <Er*********@sun.comwrote:

By the way: Elsethread, someone mentioned using NULL as
a sentinel to mark the end of the list of optional arguments.
Thought question: Why is this a bad idea, and how could it
be made better? (Hint: What is the type of the expression
the NULL macro expands to?)

I assume you're talking about the general case - obviously NULL as a
sentinel could not work for a function such as printf() where the
type of each argument varies. I fail to see how using a sentinel
value to terminate a list of arguments *of the same type* is a bad
idea and I assume that's not what you were getting at.
I think his point is that you need to cast NULL to void* when passing
to a varargs function because it may be just a naked 0 and int may be
smaller than void*. I didn't make up the code in question, it
preceeded me. But fixing it (with a cast or some other approach)
doesn't seem worthwhile to me as it is unlikely to break any time soon.

What do you mean by "any time soon"? It could break the moment you
recompile it on a 64-bit platform.
The code in question is in a rather stable state (past QA/load
tested/released to customers). Changing a few hundred lines with no
actual functional defect would clearly not be approved -- and rightly
so I think. I don't consider fixing this critical, just something to
keep in mind, particularly for when we migrate to 64 bits, where no
doubt other code will be destabilized too. With our current headers,
wouldn't matter even then for our C files, as NULL is defined as
(void*) 0, but those system headers could change too, and as our
sources include both C and C++ it will break at least in the C++ files
as NULL there is 0...
You don't actually have to wait for the code to fail before you fix
it.
Depending on the state of a project and the perceived risk of the
failure, sometimes you do.

-David

Oct 26 '06 #15
"David Resnick" <ln********@gmail.comwrites:
Keith Thompson wrote:
[...]
>You don't actually have to wait for the code to fail before you fix
it.

Depending on the state of a project and the perceived risk of the
failure, sometimes you do.
Fair enough.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Oct 26 '06 #16
Keith Thompson <ks***@mib.orgwrote:
The point is that we don't *know* the type of the expression the NULL
macro expands to; it could be either int or void* (there are other
possibilities).
"(void*)NULL" is a better sentinel value.
Agreed, I appreciate the clarification.

--
C. Benson Manica | I *should* know what I'm talking about - if I
cbmanica(at)gmail.com | don't, I need to know. Flames welcome.
Oct 27 '06 #17

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Suzanne Vogel | last post by:
'stdarg.h' defines the 'va_arg' type to use in passing variable numbers of parameters to functions. The example of its use given in the Dinkumware documentation *seems* to imply that the 'va_arg'...
4
by: Derek Baker | last post by:
I have this code which compiles on the MINGW version of GCC 3.4.2: vector<string> Labels ; va_list va_Labels; va_start(va_Labels, Number); for(int i= 0; i< Number; ++i) {...
99
by: Glen Herrmannsfeldt | last post by:
I was compiling a program written by someone else about six years ago, and widely distributed at the time. It also includes makefiles for many different systems, so I know it has been compiled...
15
by: Mark | last post by:
Hi all My c is a bit rusty and my brain is dead! Can anyone tell me why the following trys to print when I call pferror(E1); ... #include <stdio.h> #include <stdarg.h>
5
by: mdh | last post by:
May I clarify a few things about va_arg? Given: va_list ap; int ival; assume va_start initialized;
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
0
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
0
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.