By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
457,865 Members | 1,365 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 457,865 IT Pros & Developers. It's quick & easy.

Dynamic no. of arguments

P: n/a
Is it possible through some trickery, perhaps using the methods of
stdarg, to pass a dynamic (unknown at compile time) number of
arguments to a function? For example, I want to enumerate an array of
values and then pass them all to sprintf. I wouldn't want to write an
explicit check for each amount of variables that I might want to send,
nor write my own sprintf function that takes an array. Can it be done?
Jun 27 '08 #1
Share this Question
Share on Google+
18 Replies


P: n/a
On Jun 10, 8:29*pm, squaretrian...@hotmail.co.uk wrote:
Is it possible through some trickery, perhaps using the methods of
stdarg, to pass a dynamic (unknown at compile time) number of
arguments to a function? *For example, I want to enumerate an array of
values and then pass them all to sprintf. *I wouldn't want to write an
explicit check for each amount of variables that I might want to send,
nor write my own sprintf function that takes an array. *Can it be done?
Probably, I don't understand your question properly. Maybe 15.3,4
From the C-FAQ will help:

15.4: How can I write a function that takes a variable number of
arguments?

A: Use the facilities of the <stdarg.hheader.

Here is a function which concatenates an arbitrary number of
strings into malloc'ed memory:

#include <stdlib.h/* for malloc, NULL, size_t */
#include <stdarg.h/* for va_ stuff */
#include <string.h/* for strcat et al. */

char *vstrcat(const char *first, ...)
{
size_t len;
char *retbuf;
va_list argp;
char *p;

if(first == NULL)
return NULL;

len = strlen(first);

va_start(argp, first);

while((p = va_arg(argp, char *)) != NULL)
len += strlen(p);

va_end(argp);

retbuf = malloc(len + 1); /* +1 for trailing \0 */

if(retbuf == NULL)
return NULL; /* error */

(void)strcpy(retbuf, first);

va_start(argp, first); /* restart; 2nd scan */

while((p = va_arg(argp, char *)) != NULL)
(void)strcat(retbuf, p);

va_end(argp);

return retbuf;
}

Usage is something like

char *str = vstrcat("Hello, ", "world!", (char *)NULL);

Note the cast on the last argument; see questions 5.2 and 15.3.
(Also note that the caller must free the returned, malloc'ed
storage.)

References: K&R2 Sec. 7.3 p. 155, Sec. B7 p. 254; ISO Sec. 7.8;
Rationale Sec. 4.8; H&S Sec. 11.4 pp. 296-9; CT&P Sec. A.3 pp.
139-141; PCS Sec. 11 pp. 184-5, Sec. 13 p. 242.

15.5: How can I write a function that takes a format string and a
variable number of arguments, like printf(), and passes them to
printf() to do most of the work?

A: Use vprintf(), vfprintf(), or vsprintf().

Here is an error() function which prints an error message,
preceded by the string "error: " and terminated with a newline:

#include <stdio.h>
#include <stdarg.h>

void error(const char *fmt, ...)
{
va_list argp;
fprintf(stderr, "error: ");
va_start(argp, fmt);
vfprintf(stderr, fmt, argp);
va_end(argp);
fprintf(stderr, "\n");
}

References: K&R2 Sec. 8.3 p. 174, Sec. B1.2 p. 245; ISO
Secs. 7.9.6.7,7.9.6.8,7.9.6.9; H&S Sec. 15.12 pp. 379-80; PCS
Sec. 11 pp. 186-7.

Jun 27 '08 #2

P: n/a
sq************@hotmail.co.uk said:
Is it possible through some trickery, perhaps using the methods of
stdarg, to pass a dynamic (unknown at compile time) number of
arguments to a function?
Put the values in an array, and pass a pointer (to the array's first
element) to the function, along with a count. In the function itself, use
a loop to process the data.
For example, I want to enumerate an array of
values and then pass them all to sprintf. I wouldn't want to write an
explicit check for each amount of variables that I might want to send,
nor write my own sprintf function that takes an array. Can it be done?
Write a wrapper that uses the technique given above to receive the data and
passes it to sprintf in a loop. Be real sure you have enough space to
store all the data in the string.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Jun 27 '08 #3

P: n/a
On Jun 11, 8:29 am, squaretrian...@hotmail.co.uk wrote:
Is it possible through some trickery, perhaps using the methods of
stdarg, to pass a dynamic (unknown at compile time) number of
arguments to a function? For example, I want to enumerate an array of
values and then pass them all to sprintf. I wouldn't want to write an
explicit check for each amount of variables that I might want to send,
nor write my own sprintf function that takes an array. Can it be done?
From your requirements, it looks like vsnprintf can do the trick for
you.
Whiel using the v*f family of functions, one thing to be taken care of
is
va_start() and va_end() has to be called explicitly. Forgetting to
call
va_end() may result in undefined behavior.

Quoting the manual:
The functions vprintf(), vfprintf(), vsprintf(), vsnprintf()
are equivalent to the func-
tions printf(), fprintf(), sprintf(), snprintf(),
respectively, except that they are
called with a va_list instead of a variable number of
arguments. These functions do not
call the va_end macro. Consequently, the value of ap is
undefined after the call. The
application should call va_end(ap) itself afterwards.
Jun 27 '08 #4

P: n/a
sq************@hotmail.co.uk wrote:
>
Is it possible through some trickery, perhaps using the methods
of stdarg, to pass a dynamic (unknown at compile time) number of
arguments to a function? For example, I want to enumerate an
array of values and then pass them all to sprintf. I wouldn't
want to write an explicit check for each amount of variables that
I might want to send, nor write my own sprintf function that
takes an array. Can it be done?
Yes, we do it all the time with lists. For trickless example:

struct listobj {
struct listobj *next;
void *datum;
}

/* ... */

void operateon(struct listobj *root) {
while (root) {
/* do things with root->datum */
root = root->next;
}
} /* operateon */

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
** Posted from http://www.teranews.com **
Jun 27 '08 #5

P: n/a
On Jun 11, 7:30 am, CBFalconer <cbfalco...@yahoo.comwrote:
squaretrian...@hotmail.co.uk wrote:
Is it possible through some trickery, perhaps using the methods
of stdarg, to pass a dynamic (unknown at compile time) number of
arguments to a function? For example, I want to enumerate an
array of values and then pass them all to sprintf. I wouldn't
want to write an explicit check for each amount of variables that
I might want to send, nor write my own sprintf function that
takes an array. Can it be done?

Yes, we do it all the time with lists. For trickless example:

struct listobj {
struct listobj *next;
void *datum;

}

/* ... */

void operateon(struct listobj *root) {
while (root) {
/* do things with root->datum */
root = root->next;
}

} /* operateon */
That's passing a single argument that is the head of a linked list. I
was talking about passing an unknown number of arguments to a function
that uses ellipses. Hence why I mention sprintf.
Jun 27 '08 #6

P: n/a
On Jun 11, 5:55 am, Richard Heathfield <r...@see.sig.invalidwrote:
squaretrian...@hotmail.co.uk said:
Is it possible through some trickery, perhaps using the methods of
stdarg, to pass a dynamic (unknown at compile time) number of
arguments to a function?

Put the values in an array, and pass a pointer (to the array's first
element) to the function, along with a count. In the function itself, use
a loop to process the data.
For example, I want to enumerate an array of
values and then pass them all to sprintf. I wouldn't want to write an
explicit check for each amount of variables that I might want to send,
nor write my own sprintf function that takes an array. Can it be done?

Write a wrapper that uses the technique given above to receive the data and
passes it to sprintf in a loop. Be real sure you have enough space to
store all the data in the string.
No, I want sprintf to be only called once. My situation is that I
have an interpreted language that I want to add an sprintf function
for, the internal function for which accepts a list of arguments in an
array, and then simply passes it on to the standard c library's own
sprintf function, _somehow_ passing that array off as the last
argument to sprintf and having it accept it. I don't want to have to
iterate the string or array nor call sprintf repeatedly.

I'm guessing this is not possible.
Jun 27 '08 #7

P: n/a
sq************@hotmail.co.uk writes:
On Jun 11, 7:30 am, CBFalconer <cbfalco...@yahoo.comwrote:
>squaretrian...@hotmail.co.uk wrote:
Is it possible through some trickery, perhaps using the methods
of stdarg, to pass a dynamic (unknown at compile time) number of
arguments to a function? For example, I want to enumerate an
array of values and then pass them all to sprintf. I wouldn't
want to write an explicit check for each amount of variables that
I might want to send, nor write my own sprintf function that
takes an array. Can it be done?

Yes, we do it all the time with lists. For trickless example:
[example snipped]
>>

That's passing a single argument that is the head of a linked list. I
was talking about passing an unknown number of arguments to a function
that uses ellipses. Hence why I mention sprintf.
It's not possible to *directly* pass a dynamic number of arguments in
a function call. When you write the call in your source code, that
call includes a number of arguments; that number is fixed when you
write it.

There are various indirect ways to accomplish the same thing.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Jun 27 '08 #8

P: n/a
sq************@hotmail.co.uk wrote:
Is it possible through some trickery, perhaps using the methods of
stdarg, to pass a dynamic (unknown at compile time) number of
arguments to a function? For example, I want to enumerate an array of
values and then pass them all to sprintf. I wouldn't want to write an
explicit check for each amount of variables that I might want to send,
nor write my own sprintf function that takes an array. Can it be done?
No. A function call supplies a fixed number of argument
values, and that number cannot be changed after compilation.
"Variadic" functions can be called with different numbers of
arguments, but that just means that they can be called from
many different sites whose fixed argument counts disagree with
each other.

Some compilers provide ways to construct argument lists on
the fly and to pass them to called functions, but the mechanisms
(if they exist at all) are compiler-specific extensions to C
and not part of the language. You should use such things only
if (1) they solve your larger problem, (2) there's no hope of
solving your problem by standard means, (3) you don't mind tying
your code forever to one particular compiler, and (4) the
capability actually exists.

From what you've described, I'm not convinced your need
meets criterion #1 and am virtually certain it doesn't pass #2.
You want to pass an array of values to one sprintf() call --
well, what does the format string look like? If you need a
loop to build a format string with the right number of "%d"'s
in it, why not just sprintf() the array's values one by one in
the loop? Why work extra hard to use a non-portable construct
in preference to a simpler and entirely portable construct?

--
Er*********@sun.com
Jun 27 '08 #9

P: n/a
On Jun 11, 6:13 pm, Eric Sosman <Eric.Sos...@sun.comwrote:
You want to pass an array of values to one sprintf() call --
well, what does the format string look like? If you need a
loop to build a format string with the right number of "%d"'s
in it, why not just sprintf() the array's values one by one in
the loop? Why work extra hard to use a non-portable construct
in preference to a simpler and entirely portable construct?
It wasn't about meeting a need; I just idly wondered if it could be
done. :)
Jun 27 '08 #10

P: n/a
sq************@hotmail.co.uk wrote:
CBFalconer <cbfalco...@yahoo.comwrote:
>squaretrian...@hotmail.co.uk wrote:
>>Is it possible through some trickery, perhaps using the methods
of stdarg, to pass a dynamic (unknown at compile time) number of
arguments to a function? For example, I want to enumerate an
array of values and then pass them all to sprintf. I wouldn't
want to write an explicit check for each amount of variables that
I might want to send, nor write my own sprintf function that
takes an array. Can it be done?

Yes, we do it all the time with lists. For trickless example:

struct listobj {
struct listobj *next;
void *datum;
}

/* ... */

void operateon(struct listobj *root) {
while (root) {
/* do things with root->datum */
root = root->next;
}

} /* operateon */

That's passing a single argument that is the head of a linked list.
I was talking about passing an unknown number of arguments to a
function that uses ellipses. Hence why I mention sprintf.
No, that is passing an unknown number of arguments for processing,
controlled only by the length of the list. If you wish, you can
have the caller form the list, and you can have the user destroy
it. Think about it.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
** Posted from http://www.teranews.com **
Jun 27 '08 #11

P: n/a
CBFalconer <cb********@yahoo.comwrites:
sq************@hotmail.co.uk wrote:
>CBFalconer <cbfalco...@yahoo.comwrote:
>>squaretrian...@hotmail.co.uk wrote:

Is it possible through some trickery, perhaps using the methods
of stdarg, to pass a dynamic (unknown at compile time) number of
arguments to a function? For example, I want to enumerate an
array of values and then pass them all to sprintf. I wouldn't
want to write an explicit check for each amount of variables that
I might want to send, nor write my own sprintf function that
takes an array. Can it be done?

Yes, we do it all the time with lists. For trickless example:

struct listobj {
struct listobj *next;
void *datum;
}

/* ... */

void operateon(struct listobj *root) {
while (root) {
/* do things with root->datum */
root = root->next;
}

} /* operateon */

That's passing a single argument that is the head of a linked list.
I was talking about passing an unknown number of arguments to a
function that uses ellipses. Hence why I mention sprintf.

No, that is passing an unknown number of arguments for processing,
controlled only by the length of the list. If you wish, you can
have the caller form the list, and you can have the user destroy
it. Think about it.
No, that is passing a single argument, where an "argument" is an
"expression in the comma-separated list bounded by the parentheses in
a function call expression" (C99 3.3).

The called function can, of course, use the value of that argument to
access an arbitrary number of nodes in the linked list. This may be
just as good for most purposes as actually passing an arbitrary number
of arguments. However, it doesn't directly address the OP's query
about passing an arbitrary list of arguments to sprintf.

I was thinking that vsprintf() might be helpful, but I don't see any
way to build the required va_list dynamically.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Jun 27 '08 #12

P: n/a
On 12 Jun 2008 at 1:33, Keith Thompson wrote:
CBFalconer <cb********@yahoo.comwrites:
[snip garbage]
However, it doesn't directly address the OP's query about passing an
arbitrary list of arguments to sprintf.
No surprise there then.

The OP could find out what the calling conventions are on his system,
and use inline assembly to (let's say) push some number of arguments
to be determined at runtime onto the stack, and call sprintf.

Jun 27 '08 #13

P: n/a
On Jun 10, 8:29*pm, squaretrian...@hotmail.co.uk wrote:
Is it possible through some trickery, perhaps using the methods of
stdarg, to pass a dynamic (unknown at compile time) number of
arguments to a function?
There is no portable way to call an arbitrarily declared function.

Being able to do such a thing, however, is very useful in the
implementation of high level programming languages which need dynamic
foreign function calling (in both directions).

Bruno Haible has developed a collection of libraries for doing this:

http://directory.fsf.org/project/ffcall/

This is GPLed stuff, though, and though it's ported to a number of
architectures, the list is far from exhaustive. But this project does
give us an API for doing this, and proves that it's feasible by
demonstrating a working implementation that is used in real projects.
Jun 27 '08 #14

P: n/a
In article <sl*******************@nospam.invalid>,
Antoninus Twink <no****@nospam.invalidwrote:
>On 12 Jun 2008 at 1:33, Keith Thompson wrote:
>CBFalconer <cb********@yahoo.comwrites:
[snip garbage]
>However, it doesn't directly address the OP's query about passing an
arbitrary list of arguments to sprintf.

No surprise there then.

The OP could find out what the calling conventions are on his system,
and use inline assembly to (let's say) push some number of arguments
to be determined at runtime onto the stack, and call sprintf.
Actually, the real answer to the OP's question is: avcall
Google it.

It works on all the common major platforms, and is quite well done.

Jun 27 '08 #15

P: n/a

<sq************@hotmail.co.ukwrote in message
news:6b**********************************@m36g2000 hse.googlegroups.com...
On Jun 11, 5:55 am, Richard Heathfield <r...@see.sig.invalidwrote:
>squaretrian...@hotmail.co.uk said:
Is it possible through some trickery, perhaps using the methods of
stdarg, to pass a dynamic (unknown at compile time) number of
arguments to a function?
>Write a wrapper that uses the technique given above to receive the data
and
passes it to sprintf in a loop. Be real sure you have enough space to
store all the data in the string.

No, I want sprintf to be only called once. My situation is that I
have an interpreted language that I want to add an sprintf function
for, the internal function for which accepts a list of arguments in an
array, and then simply passes it on to the standard c library's own
sprintf function, _somehow_ passing that array off as the last
argument to sprintf and having it accept it. I don't want to have to
iterate the string or array nor call sprintf repeatedly.

I'm guessing this is not possible.
I had a similar requirement. My quick-fix solution was just to allow for a
reasonable maximum number of arguments (I used 6), and always call sprintf
with all the arguments. The language in this case would allow unneeded
arguments to be omitted (defaulting to 0 I think).

This works if sprintf does not complain about supplied arguments that are
not used in the format string. The library function for this (in the
language in question) looks like:

FUNCTION SSPRINTF(a,b,c,d,e,f)=
x:=getstringbuffer
sprintf(x,a,b,c,d,e)
return makestring(x)
END

And is used like this:

caption:=ssprintf("Size: %d x %d",w,h)

(sprintf() could of course be called directly with the right number of
arguments, but the way string buffers are used in C made that awkward as you
can see.)

--
Bartc
Jun 27 '08 #16

P: n/a
"Bartc" <bc@freeuk.comwrites:
<sq************@hotmail.co.ukwrote in message
news:6b**********************************@m36g2000 hse.googlegroups.com...
>On Jun 11, 5:55 am, Richard Heathfield <r...@see.sig.invalidwrote:
>>squaretrian...@hotmail.co.uk said:

Is it possible through some trickery, perhaps using the methods of
stdarg, to pass a dynamic (unknown at compile time) number of
arguments to a function?
>>Write a wrapper that uses the technique given above to receive the data
and
passes it to sprintf in a loop. Be real sure you have enough space to
store all the data in the string.

No, I want sprintf to be only called once. My situation is that I
have an interpreted language that I want to add an sprintf function
for, the internal function for which accepts a list of arguments in an
array, and then simply passes it on to the standard c library's own
sprintf function, _somehow_ passing that array off as the last
argument to sprintf and having it accept it. I don't want to have to
iterate the string or array nor call sprintf repeatedly.

I'm guessing this is not possible.

I had a similar requirement. My quick-fix solution was just to allow for a
reasonable maximum number of arguments (I used 6), and always call sprintf
with all the arguments. The language in this case would allow unneeded
arguments to be omitted (defaulting to 0 I think).

This works if sprintf does not complain about supplied arguments that are
not used in the format string. The library function for this (in the
language in question) looks like:

FUNCTION SSPRINTF(a,b,c,d,e,f)=
x:=getstringbuffer
sprintf(x,a,b,c,d,e)
return makestring(x)
END

And is used like this:

caption:=ssprintf("Size: %d x %d",w,h)

(sprintf() could of course be called directly with the right number of
arguments, but the way string buffers are used in C made that awkward as you
can see.)
Say, that's pretty good; I should have thought of it myself.

In fact, the standard guarantees that any excess arguments that aren't
consumed by the format string are ignored.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Jun 27 '08 #17

P: n/a

"Keith Thompson" <ks***@mib.orgwrote in message
news:ln************@nuthaus.mib.org...
"Bartc" <bc@freeuk.comwrites:
><sq************@hotmail.co.ukwrote in message
news:6b**********************************@m36g200 0hse.googlegroups.com...
>>On Jun 11, 5:55 am, Richard Heathfield <r...@see.sig.invalidwrote:
squaretrian...@hotmail.co.uk said:

Is it possible through some trickery, perhaps using the methods of
stdarg, to pass a dynamic (unknown at compile time) number of
arguments to a function?
>>No, I want sprintf to be only called once. My situation is that I
>I had a similar requirement. My quick-fix solution was just to allow for
a
reasonable maximum number of arguments (I used 6), and always call
sprintf
with all the arguments. The language in this case would allow unneeded
arguments to be omitted (defaulting to 0 I think).

This works if sprintf does not complain about supplied arguments that are
not used in the format string. The library function for this (in the
language in question) looks like:
Say, that's pretty good; I should have thought of it myself.

In fact, the standard guarantees that any excess arguments that aren't
consumed by the format string are ignored.
I suppose if the OP knows there are N arguments, there could be N separate
calls to sprintf, controlled by a switch, each with the right number of
arguments. Up to a reasonable limit anyway.

That fixes the minor performance hit of passing extra parameters, and would
have bypassed the problem of unused parameters, if it had been one.

Not elegant but there aren't too many library functions with a variable
parameter list.

--
Bartc
Jun 27 '08 #18

P: n/a
On Jun 11, 4:29*am, squaretrian...@hotmail.co.uk wrote:
Is it possible through some trickery, perhaps using the methods of
stdarg, to pass a dynamic (unknown at compile time) number of
arguments to a function? *For example, I want to enumerate an array of
values and then pass them all to sprintf. *I wouldn't want to write an
explicit check for each amount of variables that I might want to send,
nor write my own sprintf function that takes an array. *Can it be done?
You have an argument string, and a sequence of arguments. Look at the
definition of format strings, then write some code that scans the
format string to the first % character starting a format, figure out
the complete format (that is not too difficult), then call sprintf to
print a single argument. Then go on with the next argument.

sprintf is dangerous. In an interpreted language you wouldn't want to
allow dangerous things like passing a double to a %s argument. I think
there is one format specifier that actually expects an int* and stores
a value there. Allowing that unchecked could easily make your program
crash and could likely lead to ugly exploits.
Jun 27 '08 #19

This discussion thread is closed

Replies have been disabled for this discussion.