How to prepend formatted data to an printf() call - c

I want to implement a variadic function which behaves like printf, except that it prints some prefix. For example, let's say I want the prefix to be the value of time(0). if I call:
wrapped_printf("Hello, world %d", 5678);
I'll expect something like:
1571441246 Hello, world 5678
as the output.
Obviously, replacing the format string is not a big deal; it's the variadic business that's giving me trouble. Should I implement this as a function taking ...? Taking a va_list? And how do I prepend my extra arguments?
This is what I have right now. It compiles and runs (it's valid C89 even...), but the extra arguments get messed up.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>
int wrapped_printf(const char* format_str, ...)
{
static const char* const prefix = "%d ";
static const size_t prefix_length = 3;
va_list ap;
size_t format_string_length = strlen(format_str);
char* const prefixed_format_str = malloc(format_string_length + prefix_length + 2);
/* 1 for the trailing '\0' and 1 for a line break */
if (prefixed_format_str == NULL) { exit(EXIT_FAILURE); }
strncpy(prefixed_format_str, prefix, prefix_length);
strncpy(prefixed_format_str + prefix_length, format_str, format_string_length);
prefixed_format_str[prefix_length + format_string_length] = '\n';
prefixed_format_str[prefix_length + format_string_length + 1] = '\0';
va_start(ap, format_str);
return printf(
prefixed_format_str,
(int) time(0),
ap);
va_end(ap);
}
int main()
{
wrapped_printf("Hello world %d\n", 5678);
return EXIT_SUCCESS;
}
See it failing on Coliru.
Notes:
Only one call must be made - but it can be either to printf() or vprintf().
One can use a large string buffer, sprintf() the prefix into it, then sprintf() the original arguments afterwards; but that's also not what I mean.
I don't mind using compiler-specific code - but if you suggest that, please try covering more than a single compiler on more than a single platform - and especially GCC or clang on GNU/Linux with an AMD64 processor.

It is totally not possible to prepend arguments to a va_list portably in plain C. It can be done for sure, but it would require compiler-level wizardry for each architecture and compiler and calling-convention.
For a portable way, a library like libffi and a parser for the format strings...
I suggest that if possible you'd go for a macro instead, if you're lucky enough to be on C99+; then you can prepend "%d " to the format string with compile-time string catenation and add the number in the arguments rather easily. But the format need to be a string literal for this.
Or if you really need to use a function then I don't get the restriction of not using printf separately for the prefix followed by these - the output would be line-buffered or fully-buffered so there would not likely be any difference.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>
#define wrapped_printf_macro(f_, ...) \
printf("%lld " f_, (long long)time(0), __VA_ARGS__)
int wrapped_printf(const char* format_str, ...)
{
static const char* const prefix = "%d ";
static const size_t prefix_length = 3;
va_list ap;
printf("%lld ", (long long int)time(0));
va_start(ap, format_str);
vprintf(format_str, ap);
va_end(ap);
}
int main()
{
wrapped_printf_macro("Hello world %d\n", 5678);
wrapped_printf("Hello world %d\n", 5678);
return EXIT_SUCCESS;
}

Related

Passing a dynamic set of variadic arguments to a C function [duplicate]

This question already has answers here:
In C, given a variable list of arguments, how to build a function call using them?
(4 answers)
Closed 4 years ago.
I'm trying to call a C function that takes variadic arguments, and I need to pass in a dynamic number of arguments to the function. Additionally, this is an API I can't modify without going to a lot of effort, so if there's any possible to make this work I'll take it.
As far as I can tell, va_list is not sufficient for this purpose since you can't pass a va_list where ... was written in the original function signature.
Answers for other questions like this one talk about how to pass a ... from one function to another, but that's not what I'm doing. I need to actually dynamically generate the list of arguments, I'm not getting it in as a .... Also, all the answers I can find rely being able to modify the function to take a va_list, which is not an option here.
There was also this question, which was marked as a dupe of the previous question despite not actually asking the same question. Again, the only answer suggests converting the call to use va_list which is not an option.
I would understand if the standard didn't include a way to do this, but this seems like a case where I can imagine a perfectly reasonable implementation. This isn't so different from, say, alloca. Anyway, if it's not possible, that's fine, but I'd like the SO community to realize that this isn't a dupe of this question and deserves a definitive answer.
The API I'm calling is in C, but if there's a way to do this in C++ I would consider it.
Edit: If you have these requirements, it looks like this answer using libffi is the best way to go. There does not appear to be a way to do this either in standard C or with GCC extensions otherwise.
If you use gcc compiler, you can use __builtin_va_arg_pack() or __builtin_apply(), see here.
Examples:
#include <stdio.h>
#include <stddef.h>
#include <stdarg.h>
int my_printf(const char *fmt, ...)
{
void *args = __builtin_apply_args();
void *ret = __builtin_apply((void(*)())printf, args, 100);
__builtin_return(ret);
}
extern int my2_printf(const char *, ...);
extern inline __attribute__((__always_inline__,__gnu_inline__))
int my2_printf(const char *fmt, ...) {
return printf(fmt, __builtin_va_arg_pack());
}
int main()
{
my_printf("%s %s %s %s %s\n", "Hi", "I", "am", "kamil", "!");
my2_printf("%s %s %s %s\n", "Variadic", "args", "are", "fun");
return 0;
}
#edit:
As the question is also about on how to construct a dynamic argument list and then pass it to function. You can create a function for each case you need to support and use a big switch to differentiate between them.
A example for printing an array of unknown compile size:
#include <stdio.h>
#include <stddef.h>
#include <stdarg.h>
#include <stdlib.h>
#include <boost/preprocessor/repetition/repeat.hpp>
void print_array(size_t cnt, ...)
{
va_list va;
va_start(va, cnt);
printf("%s cnt=%d :", __func__, cnt);
for (size_t i = 0; i < cnt; ++i) {
printf(" %d", va_arg(va, int));
}
va_end(va);
printf("%s\n");
}
// we support an array up to that many arguments
#define CALL_PRINT_ARRAY_MAX 128
#define CALL_PRINT_ARRAY_ARGS(z, n, text) \
, arr[n]
#define CALL_PRINT_ARRAY_DECLARE(z, n, text) \
void call_print_array_##n (int arr[]) \
{ \
print_array(n BOOST_PP_REPEAT(n, CALL_PRINT_ARRAY_ARGS, ())); \
}
BOOST_PP_REPEAT(CALL_PRINT_ARRAY_MAX, CALL_PRINT_ARRAY_DECLARE, ())
#undef CALL_PRINT_ARRAY_DECLARE
#undef CALL_PRINT_ARRAY_ARGS
int call_print_array(int arr[], size_t n)
{
switch(n) {
#define CALL_PRINT_ARRAY_CASE(z, n, text) \
case n: call_print_array_##n(arr); break;
BOOST_PP_REPEAT(CALL_PRINT_ARRAY_MAX, CALL_PRINT_ARRAY_CASE, ())
#undef CALL_PRINT_ARRAY_CASE
default:
fprintf(stderr, "Array size is too big for what we're prepared\n");
return -1;
}
return 0;
}
int main()
{
//int a1[5] = {1,2,3,4,5};
//call_print_array(a1, sizeof(a1)/sizeof(a1[0]));
size_t size;
scanf("%zu", &size); // insecure
int * a2 = calloc(size, sizeof(*a2));
for (size_t i = 0; i < size; ++i)
a2[i] = i;
call_print_array(a2, size);
return 0;
}
The easiest way to do this would be with variadic macros, kind of like the way it's done for eprintf:
#define eprintf(…) fprintf (stderr, __VA_ARGS__)
__VA_ARGS__ expands into the full argument list passed into the macro with which you can then call the other function declared with .... Unfortunately what you want to do cannot be done within a function without going through a lot of effort that you seem to want to avoid.

How can I write a function that takes a variable number of arguments (integers) and output them using stdargs?

This program accepts a finite amount of integers and outputs them using a macro provided by va_arg. (stdargs)
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
void main()
{
foo(5,3,4);
}
void foo(int i,...){
va_list argp;
va_start(argp,i);
int p;
while ((p = va_arg(argp,int))!= NULL)printf("%d",p);
va_end(argp);
}
However although no compiltation/syntax errors arise I do not get the output I want. I get this running on bash:
How can I fix my program so I get: 5,3,4?
You need to pass an explicit last value and stop on that, because va_arg is not able to detect the end of the arguments.
#include <stdarg.h>
#include <stdio.h>
void foo(int i, ...) {
va_list argp;
va_start(argp, i);
do {
printf("%d\n", i);
} while ((i = va_arg(argp, int)) != -1);
va_end(argp);
}
int main() {
foo(5, 3, 4, -1);
return 0;
}
Output:
5
3
4
You need to figure out the number of arguments somehow because va_arg does not magically know it. If you're going to be using NULL as a sentinel value, pass NULL as the last argument in the list.
foo(5,3,4, NULL);
Secondly, you're ignoring the first argument, i, so it only prints out 34. If you mean to use i as the number of arguments passed, then use a for loop instead.
Other minor things:
int main() instead of void main()
Forward declare void foo(int i,...);.

Printing only integer arguments in variable argument function in C

I want to write a C function, which can take any number of arguments and print value of int arguments only. I saw va_list and va_arg in stdarg.h, but I couldn't find any mechanism to get the number of arguments. I cannot take first argument as the number of arguments.
There's no portable way in standard C to get the number of arguments in variable argument functions.
The common way to solve it is to use the rightmost parameter parmN to provide the number of integers explicitly. For instance, your function prototype may look like this:
int foo(int number, ...);
But this is not an option to you according to your question.
Reference: C FAQ: How can I discover how many arguments a function was actually called with?
There is no (portable) way to get the number of arguments in a variadic function at runtime. That number is lost at runtime (only the compiler knows it).
Notice that on common processors and application binary interfaces (ABI) convention (e.g. x86-64 ABI on Linux), the machine itself does not know at runtime the arity of the current call in C; this is also true for others x86 calling conventions. However, when the compiler is compiling a variadic call, it does know the arity at compile time (but does not emit it in the object file).
You could define the convention that your variadic function takes as first argument the number of remaining (variadic) arguments:
void print_integers (int nbints, ...);
Then you would implement it e.g.
#include <stdio.h>
#include <stdarg.h>
void print_integers (int nbints, ...)
{
va_list args;
va_start (nbints, args);
for (int ix=0; ix<nbints; ix++) {
int curarg = va_arg(args, int);
printf(" %d", curarg);
};
va_end(args);
fflush(NULL);
}
If you cannot do this, you have to customize your preprocessor or your compiler. Perhaps a job for your MELT extension (MELT is a domain specific language to extend GCC). Or perhaps use GPP as your preprocessor.
You could also play some cpp preprocessor tricks, notably stringification and concatenation and variadic macros. For instance, you might define
void print_integers_str(const char*, ...);
#define print_my_integers(...) \
print_integers_str(#__VA_ARGS__, ##__VA_ARGS__);
Then print_my_integers(x,y) gets expanded to print_integers_str("x,y", x,y) and your varadic function print_integer_str could parse the "x,y" literal string (at least count commas). But with print_my_integers(f(x,y),g(y)+/*,,*/k)you may get a nightmare.
To be short: I recommend give up that goal and do things otherwise.
Using NARGS macro (in this case limited to 8 args):
#include <stdio.h>
#include <stdarg.h>
#define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,N,...) N
#define NARGS(...) NARGS_SEQ(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1)
#define fn(...) fn(NARGS(__VA_ARGS__), __VA_ARGS__)
static void (fn)(int n, ...)
{
va_list args;
int i;
va_start(args, n);
for (i = 0; i < n; i++) {
printf("%d\n", va_arg(args, int));
}
va_end(args);
}
int main(void)
{
fn(6, 7, 8);
return 0;
}
Or you can loop until -1:
#include <stdio.h>
#include <stdarg.h>
#define fn(...) fn(0, __VA_ARGS__, -1)
static void (fn)(int n, ...)
{
va_list args;
int i;
va_start(args, n);
while (1) {
i = va_arg(args, int);
if (i == -1) break;
printf("%d\n", i);
}
va_end(args);
}
int main(void)
{
fn(6, 7, 8);
return 0;
}

C : write a function doesn't know how many parameter

When learning C I see that printf can receive many arguments as it is passed.
And I don't know how C can implement a function like this, where the user can type as many parameters as the user wants. I have thought about pointers, too but still have no bright idea. If anyone has any ideas about this type of function, please tell me.
You need to use va_args, va_list and the like.
Have a look at this tutorial.
http://www.cprogramming.com/tutorial/c/lesson17.html
That should be helpful.
You have to use the ... notation in your function declaration as the last argument.
Please see this tutorial to learn more: http://www.cprogramming.com/tutorial/c/lesson17.html
#include <stdarg.h>
#include <stdio.h>
int add_all(int num,...)
{
va_list args;
int sum = 0;
va_start(args,num);
int x = 0;
for(x = 0; x < num;x++)
sum += va_arg(args,int);
va_end(args);
return sum;
}
int main()
{
printf("Added 2 + 5 + 3: %d\n",add_all(3,2,5,3));
}
You use C varargs to write a variadic function. You'll need to include stdargs.h, which gives you macros for iterating over an argument list of unknown size: va_start, va_arg, and va_end, using a datatype: va_list.
Here's a mostly useless function that prints out it's variable length argument list:
void printArgs(const char *arg1, ...)
{
va_list args;
char *str;
if (arg1) We
va_start(args, arg1);
printf("%s ", arg1);
while ((str = va_arg(argp, char *)) != NULL)
printf("%s ", str);
va_end(args);
}
}
...
printArgs("print", "any", "number", "of", "arguments");
Here's a more interesting example that demonstrates that you can iterate over the argument list more than once.
Note that there are type safety issues using this feature; the wiki article addresses some of this.

Platform inconsistencies with vsprintf and va_list

Background: I am currently trying to "extend" standard C formatting with support for handling a certain struct, similar to how Objective-C extends C formatting to allow support for NSString with the "%#" sequence.
The one problem I'm struggling with is that vsprintf seems to be behaving differently on OS X versus Linux (I've tested with Ubuntu 10.10 and 12.04). On OS X, it is behaving how I thought it should, where after calling vsprintf, calling va_arg returns the ms pointer (as if the vsprintf function called va_arg to get the 5). On Linux, however, the va_list does not change from vsprintf, and calling va_arg returns 5.
I would really like to figure out a way to implement this functionality so that it behaves consistently across platforms. Is it wrong to assume that you can expect vsprintf to consistently change the pointer inside va_list so that the next time you call va_arg it returns the next not-yet-used argument?
I have simplified my code as much as possible to demonstrates the issue. On OS X, this code prints the correct address of the pointer returned from malloc. On Linux, the value of ms in foo becomes 5, so it prints 5.
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
static void foo(void *, ...);
typedef struct {
char *value;
} mystruct;
int main(int argc, char *argv[]) {
mystruct *ms = malloc(sizeof(mystruct));
foo(NULL, "%d %#", 5, ms);
}
void foo(void *dummy, ...) {
va_list args;
va_start(args, dummy);
char buffer[512];
int buffer_ptr = 0;
int i = 0;
char *format = va_arg(args, char *);
buffer[0] = '\0';
for (i = 0; i < strlen(format); i++) {
if (i <= strlen(format) - 1 && (format[i] == '%' && format[i+1] == '#')) {
vsprintf(buffer, buffer, args);
/* can expect the next argument to be a mystruct pointer */
mystruct *ms = va_arg(args, mystruct *);
buffer[buffer_ptr+1] = '\0';
fprintf(stderr, "%p", ms); /* SHOULD NOT PRINT 5 */
/* concatenate here */
} else {
buffer[buffer_ptr++] = format[i];
buffer[buffer_ptr] = '\0';
}
}
va_end(args);
}
You need to use va_copy if you're going to use an argument list more than once -- failure to do so is undefined behavior. Your code should look something like this:
va_list args;
va_start(args, dummy);
...
char *format = va_arg(args, char *);
...
va_list argsCopy;
va_copy(argsCopy, args);
vsprintf(..., argsCopy);
va_end(argsCopy);
...
mystruct *ms = va_arg(args, mystruct *);
...
va_end(args);
The problem is that it's up to the implementation how to implement a va_list -- it might contain all the info and state for extracting arguments directly, or it might contain a pointer to something that holds the state indirectly. So passing it to vsprintf might make a copy of all the relevant state or it might not.
What you want for what you are trying to do is a vspintf-like function that takes a va_list * rather than a va_list, so you can ensure you have the proper state after it returns. Unfortunately, the standard does not provide any such function.

Resources