C syntax to create function foo(...) - c

Sorry for the simple question, but how could I create the C-function with undefined number of parameters such as
int printf ( const char * format, ... ).
I would like to create function to use it as wrapper for printk:
void my_printk( const char * format, ...)
{
printk("my log:");
printk(format, ...);
printk("\n");
}
Thanks

You have to convert the args to a va_list before you can pass it to another function. Then you can pass it to the 'v' version of the function.
So you can do:
void my_printk( const char * format, ...)
{
va_list ap;
va_start(ap, format);
printk("my log:");
vprintk(format, ap);
printk("\n");
va_end(ap);
}
Most of the time, any function like this will provide a 'v' version, and yours should too:
void my_vprintk( const char * format, va_list ap)
{
printk("my log:");
vprintk(format, ap);
printk("\n");
}
void my_printk( const char * format, ...)
{
va_list ap;
va_start(ap, format);
my_vprintk(format, ap);
va_end(ap);
}

You're close. Have a look here: http://publications.gbdirect.co.uk/c_book/chapter9/stdarg.html
int f(int, ... );
int f(int, ... ) {
.
.
.
}
int g() {
f(1,2,3);
}

Related

pass 3 dots argument to another function

I have function called foo and that function takes ..., I want to pass all the argument that passed in ... to the function called oof, sample code:
#include <stdio.h>
#include <stdarg.h>
void oof(FILE * f, const char * fmt, ...){
va_list args;
va_start(args, fmt);
vfprintf(f, fmt, args);
va_end(args);
}
void foo(const char * fmt, ...){
oof(stdout, fmt, ...); // how can I pass the 3 dots?
// do other things in the function block
}
int main(int argc, char *argv[]){
foo("Hello %s\n", "World");
}
I don't want to pass to oof a va_list, but the arguments themselves
You need to change oof to accept a va_list and pass that.
void oof(FILE * f, const char * fmt, va_list args){
vfprintf(f, fmt, args);
}
void foo(const char * fmt, ...){
va_list args;
va_start(args, fmt);
oof(stderr, fmt, args);
va_end(args);
}
You cannot do this with a function but you can do this with a macro:
#define foo(...) oof(__VA_ARGS__)
There is still an issue.
Where do you get FILE *f argument from?
Assuming it is stdout then define the macro as:
#define foo(...) oof(stdout, __VA_ARGS__)
amd if you want to eliminate some parameters (doing the inverse of above, just do the following:
#define foo(a, b, ...) oof(__VA_ARGS__)
This is similar to dbush's answer (dbush should get the credit - do not accept my answer over theirs), but slightly modified because of OP's statement:
I don't want to pass to oof a va_list, but the arguments themselves
Because a va_list needs to be passed to something, I define a different function voof called by both oof and foo:
#include <stdio.h>
#include <stdarg.h>
void voof(FILE * f, const char * fmt, va_list args){
vfprintf(f, fmt, args);
}
void oof(FILE * f, const char * fmt, ...){
va_list args;
va_start(args, fmt);
voof(f, fmt, args);
va_end(args);
}
void foo(const char * fmt, ...){
va_list args;
va_start(args, fmt);
voof(stderr, fmt, args);
va_end(args);
}
int main(int argc, char *argv[]){
foo("Hello %s\n", "World");
}
foo and oof currently do the same thing, apart from the extra FILE * parameter in oof.

Variable argument passing in C to printf / vsprintf

I am trying to pass variable arguments that I get to another function I call.
I had written a sample code to test this.
Why is my_printf working but not my2_printf in below code?
#include <stdio.h>
#include <stdarg.h>
my2_printf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
printf(fmt, ap);
va_end(ap);
}
my_printf(const char *fmt, ...)
{
va_list ab;
va_start(ab, fmt);
vfprintf(stdout, fmt, ab);
va_end(ab);
}
main()
{
int i = 5;
my_printf("This is a test %d => %s\n", i, "done");
my2_printf("This is a test %d => %s\n", i, "done");
}
Output I get is as below:
This is a test 5 => done
This is a test -171084944 =>
Because there's variant of printf that expects a va_list argument. If you have a va_list you must use the functions with the v prefix, such as vprintf.
The call to printf leads to undefined behavior.

Variable arguments is not printing

#define TRACE2(args) TraceDebug args;
void TraceDebug ( const char * format, ... );
void TraceDebug ( const char * format, ... )
{
static char buffer[256];
va_list args;
va_start (args, format);
vsprintf (buffer,format, args);
va_end (args);
}
int main(void)
{
TRACE2(("ece %d is of %d students.", 1,33));
return 0;
}
The expected output is ece 1 is of 33 students. Why the output screen is blank?
You only print into buffer, but you don't print anything on the screen.
This is what you need:
void TraceDebug ( const char * format, ... )
{
static char buffer[256];
va_list args;
va_start (args, format);
vsprintf (buffer,format, args);
va_end (args);
printf("%s", buffer); // <<< add this
}
Or just use vprintf if you only want output on the screen.
void TraceDebug(const char * format, ...)
{
va_list args;
va_start(args, format);
vprintf(format, args); // <<<<<<<<<<<
va_end(args);
}

Is it possible to pass 2 functions which have different signature as an argument to another function?

Currently, I have the following 2 functions:
void write_to_file(FILE *fp)
{
fprintf(fp, "stuff here: %d", 10);
/* 1000s of similar lines below */
}
and
void write_to_string(char *str)
{
sprintf(str, "stuff here: %d", 10);
/* 1000s of similar lines below */
}
I'd like to poly morph it into a single function.
I'd thought about something like:
void write_somewhere(void *ptr, int to_file)
{
if (to_file) {
typedef fprintf myprintf;
} else {
typedef sprintf myprintf;
}
myprintf(ptr, "stuff here: %d", 10);
}
This doesn't work and looks ugly.
Since the signature of fprintf and sprintf are different and as follows,
int fprintf(FILE *stream, const char *format, …);
int sprintf(char *buffer, const char *format, …);
Is it possible to do something like,
void write_somewhere(void *ptr, void *func)
{
func(ptr, "stuff here: %d", 10);
}
EDIT:
Based on Alter's answer below, this is what I have but it doesn't quite work as expected and prints out garbage value when trying to print out values in write_somewhere() function:
#include <stdio.h>
#include <stdarg.h>
typedef int (*myprintf_t) (void *, const char *, ...);
int myfprintf(void *ptr, const char *format, ...)
{
va_list args;
int ret;
va_start(args, format);
ret = vfprintf(ptr, format, args);
va_end(args);
return ret;
}
int mysprintf(void *ptr, const char *format, ...)
{
va_list args;
int ret;
va_start(args, format);
ret = vsprintf(ptr, format, args);
va_end(args);
return ret;
}
void write_somewhere(void *ptr, myprintf_t myprintf, const char *format, ...)
{
va_list args;
int ret;
va_start(args, format);
ret = myprintf(ptr, format, args);
va_end(args);
return ret;
}
int main(void)
{
char s[100];
int i = 100;
/* This works */
write_somewhere(stdout, myprintf, "Hello world");
/* This prints out garbage */
write_somewhere(stdout, myprintf, "Hello world, I am %d", i);
write_somewhere(s, mysprintf);
return 0;
}
Jen‘s answer is the correct one, but in this case you can redirect ptr to v*printf using a pointer to function:
#include <stdio.h>
#include <stdarg.h>
int myfprintf(void *ptr, const char *format, ...)
{
va_list args;
int ret;
va_start(args, format);
ret = vfprintf(ptr, format, args);
va_end(args);
return ret;
}
int mysprintf(void *ptr, const char *format, ...)
{
va_list args;
int ret;
va_start(args, format);
ret = vsprintf(ptr, format, args);
va_end(args);
return ret;
}
void write_somewhere(void *ptr, int (*myprintf)(void *, const char *, ...))
{
myprintf(ptr, "stuff here");
}
int main(void)
{
char s[100];
write_somewhere(stdout, myfprintf);
write_somewhere(s, mysprintf);
return 0;
}
For your last edit:
It seems that you want to pass some extras parameters to write_somewhere, in this case I suggest:
#include <stdio.h>
#include <stdarg.h>
#define TO_FILE 0
#define TO_STRING 1
void write_somewhere(int where, void *ptr, const char *format, ...)
{
#define myprintf(ptr, ...) \
(where == TO_FILE ? vfprintf(ptr, __VA_ARGS__) : vsprintf(ptr, __VA_ARGS__))
va_list args;
va_start(args, format);
myprintf(ptr, format, args);
/* more stuff */
va_end(args);
#undef myprintf
}
int main(void)
{
char s[100];
write_somewhere(TO_FILE, stdout, "%u\n", 10);
write_somewhere(TO_STRING, s, "Hello");
printf("%s\n", s);
return 0;
}
The C language guarantees that all function pointers have the same representation. Your polymorphic functions simply needs to be prototyped as accepting any function pointer, say, a void (*funcptr)(void). Note that a ptr-to-void is not a function pointer (it's an object pointer) and may not be able to hold a function pointer.
Of course you can only call the function if you know which of the several types it is. So you need some way to discriminate, much like printf does by looking at the format. If you call a function with arguments not matching its prototype, the behavior is undefined.
Not an answer to your exact question, but instead of writing write_something() as you have, you could change the structure slightly:
void write_somewhere(void *ptr, int to_file)
{
if (to_file) {
fprintf( (FILE*) ptr, "stuff here");
} else {
sprintf( (char*) ptr, "stuff here");
}
}
However, for a strict answer to your question...
As you've found, the typedef line that you've attempted doesn't work. typedef is a compile time operation, not a runtime operation.
What you could do, though, is to define a type for a function pointer that matches both the fprintf() and sprintf() functions:
typedef int (*someprintf_ptr)(FILE *stream, const char *format, …);
The write_somewhere() would then look like:
void write_somewhere(void *ptr, someprintf_ptr func)
{
func(ptr, "stuff here");
}
/* with calls looking like... */
write_somewhere( (void *)a_file_ptr, (someprintf_ptr)(fprintf));
Your write_something function would have to be something like:
void write_something(void (*function)(), int to_file)
{
....
}
Try making myprintf a function
void write_somewhere(void *ptr, int to_file)
{
myprintf(to_file, ptr, "stuff here");
// do stuff
/* 1000s of similar lines below */
}
void myprintf( int to_file, void *ptr, char *output )
{
if (to_file)
fprintf( ptr, output );
else
sprintf( ptr, output );
}
Let me try:
struct target {
int (*tgtfunction)();
void* ptr;
}
struct target mktarget_file(FILE * fp) {
struct target tgt = { .tgtfuntion = vfprintf, .ptr = fp };
return tgt;
}
struct target mktarget_string(char * str) {
struct target tgt = { .tgtfuntion = vsprintf; .ptr = str };
return tgt;
}
void tgtprintf(struct target * target, char * fmt, ...) {
va_list ap;
va_start(ap, target);
int ret = target.tgtfunction(target.ptr, fmt, ap);
va_end(ap);
return ret;
}
void write_stuff(struct target * target)
{
tgtprintf(target, "stuff here");
/* 1000s of similar lines below */
}
should do what you want: create a struct target for your wanted target, and just call write_stuff to write your stuff there.
Be aware that the sprintf stuff might need to be refined, as each string is written to the same place instead of appended, and there is no check for free space. But the general concept could start like this.

How to print both to stdout and file in C

I read this topic, but his problem maybe different from mine
Writing to both stdout & a file
I want to write a function, that function need to print out to both stdout and a file. My C program gets user input by scanf.
I intend to write a function like printf but I don't really know how:
I tried this, but it only can work with "pure" string, can't convert %d, %.*lf (my print function only need two conversions)
void dupPrint(FILE *fp,char *string)
{
printf("%s",string);
fprintf(fp,"%s",string);
return;
}
I tried dup2 and freopen but they didn't work for me.
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
int i;
int file = open("input3.txt", O_APPEND | O_WRONLY);
if(file < 0) return 1;
if(dup2(file,1) < 0) return 1;
printf("Redirect to file!\n");
printf("enter i : ");
scanf("%d",&i);
return 0;
}
This dup2() tutorial only print to file.
I also tried tee, but may be it not work because I have to get input from user (if work, it's not "fair" because tee isn't in my program).
I think implement a printf-like will solved problem but I don't know how to convert .*lf
(print out double with user-enter precision)
#include <stdio.h>
#include <stdarg.h>
void dupPrint(FILE *fp,char *fmt, ...)
{
va_list ap;
char *p, *sval;
int ival;
double dval;
va_start (ap, fmt); //make ap point to 1st unnamed arg
for(p = fmt; *p; p++)
{
if (*p != '%') {
putchar(*p);
continue;
}
switch (*++p) {
case 'd':
ival = va_arg(ap, int);
printf("%d", ival);
break;
case '.*lf' //?????
}
}
}
Can anyone suggest a solution for my problem?
Fortunately, you don't need to. You just want to use the v variants of printf and fprintf that take a va_list instead of your passing arguments directly:
void tee(FILE *f, char const *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
va_start(ap, fmt);
vfprintf(f, fmt, ap);
va_end(ap);
}
You can implement your dupPrint function using vfprintf and va_list/ va_start / va_end.
in the mid-layer:
#define DUPPRINT(fp, fmt...) do {printf(fmt);fprintf(fp,fmt);} while(0)
in your app code:
...
DUPPRINT(fd, "%s:%d\n", val_name, val_v);
...
Use a variadic function and vprintf!
void dupPrint(FILE *fp,char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
va_start(ap, fmt);
vfprintf(fp, fmt, ap);
va_end(ap);
}
Optionally, implement vdupPrint, have dupPrint call vdupPrint, and use va_copy (if C99 is available) to duplicate the va_list instead of the stop-and-restart method I used. (If va_copy is not available to you, you'll have to start two separate va_lists and pass them both to vdupPrint, which is a sub-optimal solution but will work for C89 safely.)

Resources