Dynamic no. of arguments

S

squaretriangle

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?
 
U

user923005

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.h> header.

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.
 
R

rahul

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.
 
S

squaretriangle

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.
 
S

squaretriangle

(e-mail address removed) said:


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.


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.
 
K

Keith Thompson

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.
 
S

squaretriangle

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. :)
 
K

Keith Thompson

CBFalconer said:
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.
 
A

Antoninus Twink

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.
 
K

Kaz Kylheku

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.
 
K

Kenny McCormack

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.
 
B

Bartc

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.)
 
K

Keith Thompson

Bartc said:
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.
 
B

Bartc

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.
 
C

christian.bau

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top