How to pass variable number of arguments to printf/sprintf
void Error(const char* format, ...)
{
va_list argptr;
va_start(argptr, format);
vfprintf(stderr, format, argptr);
va_end(argptr);
}
If you want to manipulate the string before you display it and really do need it stored in a buffer first, use vsnprintf
instead of vsprintf
. vsnprintf
will prevent an accidental buffer overflow error.
Pass varargs to printf
Use vprintf
, which is declared as:
int vprintf(const char *format, va_list ap);
In your log
function, invoke va_start
to obtain a va_list
value, then pass that value to vprintf
.
Since your log
function takes a FILE*
argument, you'll probably want to use vfprintf
rather than vprintf
(and perhaps update your question to ask about fprintf
rather than printf
).
Incidentally, you might want to reconsider using the name log
; that's the name of a standard function declared in <math.h>
.
Reflecting your updated question, you can print the timestamp inside log
by calling fprintf
directly:
va_list(args);
fprintf(f, "%s - ", now());
va_start(args, format);
vfprintf(f, format, args);
how to print a variable number of arguments in r?
The doc is right. In first case, do.call(sprintf, c(list("%s %s"), vec))
is equal to:
sprintf("%s %s", "a","b","c","d")
The fmt string "%s %s"
requires two vectors while you provided four and the last two ("c", "d") were not used for printing.
The second case is similar. do.call(sprintf, c(fmt = base_string, as.list(v1)))
is equal to:
sprintf(fmt = "%s, %s, %s", "foo", "bar", "baz","foo", "bar", "baz")
Three variables were to be printed based on fmt
but you provided six.
Then, what does "recycled" in the doc mean?
and I guess you might misunderstand it. It means when the formating string and vectors are of different lengths, the short er ones will be recycled to the longest one. An example:
> sprintf(c('%s %s', '%s, %s'), c('a', 'b', 'c'), 1:6)
[1] "a 1" "b, 2" "c 3" "a, 4" "b 5" "c, 6"
How to print variable number of arguments: You can try paste
:
> sprintf(paste0(vec, collapse = ' '))
[1] "a b c d"
> sprintf(paste0(v1, collapse = ', '))
[1] "foo, bar, baz, foo, bar, baz"
How can I pass variable number of arguments to sprintf() function?
What you want is probably the vsprintf
function. It takes an array as the set of arguments. So in your case, you'd have something like this:
$args = <array_of_chosen_options>;
$fmt = trim(str_repeat("%s ", count($args)));
$result = vsprintf($fmt, $args);
Printing a variable number of arguments to a format string
As others said there is no direct way of doing that. You can build your own function which dumps the values of strings at the correct format specifiers. Below function makes a temporary format string for each %s
and appends it to the earlier build string using snprintf()
.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXBUF 4096
char *strmaker(char* format, int num_args, char** strings)
{
char* prnt = calloc(sizeof(char), MAXBUF);
int prnt_ct = 0;
char* tmp_fmt = malloc(strlen(format) + 1); // Prepare for the worst case (format == tmp_fmt).
int fmt_ct = 0;
/* Append the strings to the prnt buffer */
for (int i = 0; i < num_args; i++) {
char* s_loc = strstr(format + fmt_ct, "%s"); // Search the format-string for string specifier (%s)
if (s_loc == NULL)
return prnt;
int tmp_fmt_len = (int) (s_loc + 2 - format - fmt_ct); // +2 for %s
strncpy(tmp_fmt, format + fmt_ct, tmp_fmt_len); // Make tmp_fmt
tmp_fmt[tmp_fmt_len] = '\0';
fmt_ct = fmt_ct + tmp_fmt_len;
int p_return = snprintf(prnt + prnt_ct, MAXBUF - prnt_ct, tmp_fmt, strings[i]); // If no error, return the number characters printed excluding nul (man page)
if (p_return >= MAXBUF - prnt_ct) // If buffer overflows (man page)
return prnt;
prnt_ct = prnt_ct + p_return; // Update the index location.
}
return prnt;
}
int main(int argc, char *argv[]) // Pass format and arguments
{
if (argc <= 1)
return -1;
char *s = strmaker(argv[1], argc - 2, argv + 2);
printf("%s\n", s);
free(s);
return 0;
}
Terminal Session:
$ ./a.out '%s %s %s' 1 2 3
1 2 3
$ ./a.out 'one %s two %s three %s' 1 2 3
one 1 two 2 three 3
$ ./a.out 'one %s two %s three' 1 2 3
one 1 two 2
$ ./a.out 'one %s two %s three %s' 1 2
one 1 two 2
printf - Can I pass all the variadic arguments as a pointer instead of one-by-one on the stack?
A solution will involve writing your own format string parser that interprets the format specifiers with data width to extract from the binary blob, such that each format specifier caused the data index to be incremented, and the correct type to be extracted and printed.
Superficially the function vprintf appears close to what you need, but is not viable. It takes a single va_list
argument which normally you create from a ...
var-arg list using using va_start
, but in your case the input is not a var-arg list, so it is unlikely to work directly on the binary data without first unpacking your binary data - other than by dumb luck, and even then certainly not portable.
The (or at least one) problem with vprintf
is a var-arg list is unlikely to be aligned in the same manner as your binary blob; stacked arguments are likely to have fixed alignment and not be contiguous.
The approach I'd suggest here is to parse the format string, print each non-format specifier character directly, extract format specifiers completely (with all modifiers), determine the width/type from the specifier, extract that much data into an appropriate data type, print that single data item using the whole format specifier, and increment the data index by the width. Continue like that for the entire format string. It is a lot of work - you'd have to be doing a lot of this to justify the effort - but you only write it once, and it would be generic so may make maintenance simpler.
Note:
My motivation for wanting such a solution is faster post-processing thanks to less copying of the data.
That is a poor reason; it will have negligible performance impact. It is better justified by the simplicity and convenience of encoding arbitrary data structure of the binary blob in the format string. This may have a significant development, readability and maintenance impact if you have a lot of code like this with many varying data structures to encode.
How to resolve variable number of arguments problem of printf if reverse printing is not allowed
If you were to design a new compiler for a different calling convention, you could have the compiler push the number of actual arguments with which the call was done, or set that number in a specific register such as RAX/EAX, which will be overridden anyway.
Another option would be to redefine the printf()
API to have the format string as the last parameter. In this way you will have all you need to access the stack looking for your parameters.
Variable number of arguments in C programmng
I want to use functions like sum(1,2,3) should return 6. i.e, no counter should be there
You could define a sentinel. In this case 0
might make sense.
/* Sums up as many int as required.
Stops adding when seeing the 1st 0. */
int sum(int i, ...)
{
int s = i;
if (s)
{
va_list ap;
va_start(ap, i);
/* Pull the next int from the parameter list and if it is
equal 0 leave the while-loop: */
while ((i = va_arg(ap, int)))
{
s += i;
}
va_end(ap);
}
return s;
}
Call it like this:
int sum(int i, ...);
int main(void)
{
int s = sum(0); /* Gives 0. */
s = sum(1, 2, 3, 0); /* Gives 6. */
s = sum(-2, -1, 1, 2, 0); /* Gives 0. */
s = sum(1, 2, 3, 0, 4, 5, 6); /* Gives 6. */
s = sum(42); /* Gives undefined behaviour! */
}
The sum()
function alternatively could also look like this (but would do one useless addition of 0):
/* Sums up as many int as required.
Stops adding when seeing the 1st 0. */
int sum(int i, ...)
{
int s = i;
if (s)
{
va_list ap;
va_start(ap, i);
/* Pull the next int from the parameter list and if it is
equal 0 leave the do-loop: */
do
{
i = va_arg(ap, int);
s += i;
} while (i);
va_end(ap);
}
return s;
}
How to write a function with a variable number of arguments that are passed to printf
Use an intermediate variable (here substr
) to build the functional message (date message) and a second buid for the technical message (error message):
#! /bin/bash
declare -r script_name="tmp.bash"
function print_error {
local substr=
printf -v substr "$1" "${@:2}"
printf "%s: ERROR: %s\n" "$script_name" "$substr"
}
print_error "Today is %s; tomorrow is %s" "$(date)" "$(date -d "+1 day")"
Than, you can separate functional and technical builds:
#! /bin/bash
declare -r script_name="tmp.bash"
function print_tech_error () {
printf "%s: ERROR: %s\n" "$script_name" "$1"
}
function print_fct_error {
local substr=
printf -v substr "$1" "${@:2}"
print_tech_error "${substr}"
}
print_fct_error "Today is %s; tomorrow is %s" "$(date)" "$(date -d "+1 day")"
Related Topics
How Are References Implemented Internally
How to Call the Base Class Constructor
Is Is_Constexpr Possible in C++11
Fastest Way to Get Ipv4 Address from String
Virtual Function Default Arguments Behaviour
How to Read a Complete Line from the User Using Cin
Why Does Std::Cout Output Disappear Completely After Null Is Sent to It
Dealing With Accuracy Problems in Floating-Point Numbers
Printing 1 to 1000 Without Loop or Conditionals
Appending a Vector to a Vector
How Does Photoshop Blend Two Images Together
The Program Can't Start Because Libgcc_S_Dw2-1.Dll Is Missing
Do Distinct Functions Have Distinct Addresses
Why Can't We Declare a Std::Vector≪Abstractclass≫
Why Does C++11 Not Support Designated Initializer Lists as C99
Have You Used Any of the C++ Interpreters (Not Compilers)
Difference Between Angle Bracket ≪ ≫ and Double Quotes " " While Including Header Files in C++