I found the following code can add log into syslog. But if i also want to add __FUNCTION__ info to the syslog, how to do it?
openlog(basename(argv[0]), LOG_CONS | LOG_PID | LOG_NDELAY, LOG_DAEMON);
int logger(int priority, const char *format, ...) {
int result = 0;
va_list args;
va_start(args, format);
vsyslog(priority, format, args);
vfprintf(stderr, format, args);
va_end(args);
return result;
}
First, modify logger to accept the function name:
int logger_internal(const char* func, int priority, const char* format, ...);
But call it through the macro:
#define logger(priority, format, ...) \
logger_internal(__FUNCTION__, priority, format, __VA_ARGS__)
Modifying the body of logger_internal to take the extra parameter into account is a bit annoying, but not difficult. Probably the most straightforward way would be to prepend the function to the format argument; so something like (untested):
int logger_internal(const char* func, int priority, const char* format, ...) {
va_list args;
size_t func_l = strlen(func);
size_t format_l = strlen(format);
char* fmt = malloc(func_l + format_l + 2);
memcpy(fmt, func, func_l);
fmt[func_l] = ' ';
memcpy(&(fmt[func_l + 1]), format, format_l);
fmt[func_l + 1 + format_l] = '\0';
va_start(args, format);
vsyslog(priority, fmt, args);
va_end(args);
free(fmt);
}
But obviously that part would depend on what you wanted your syslog entry to look like.
Related
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.
This question already has an answer here:
C - Variable Argument with Sprintf?
(1 answer)
Closed 2 years ago.
I try to achieve same thing in vprintf function using sprintf to write into buffer, however I can not do it. What is my mistake?
#include <stdio.h>
#include <stdarg.h>
char latestPrint[1000];
int currentPositionPrint=0;
void WriteFrmtd(char *format, ...) {
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
}
void WriteToPrint(char *format, ...) {
va_list args;
va_start(args, format);
currentPositionPrint+=sprintf(currentPositionPrint+latestPrint , format, args);
va_end(args);
}
int main () {
WriteFrmtd("%d variable argument\n", 1);
WriteFrmtd("%d variable %s\n", 2, "argumentsqweqweqweqwe");
WriteToPrint("%d variable %s\n", 2, "argumentsqweqweqweqwe");
printf("%s",latestPrint);
return(0);
}
Output:
1 variable argument
2 variable argumentsqweqweqweqwe
1698242904 variable 1698242904 variable
You can use vsprintf (same as vprintf but using an array as output instead of stdout):
void WriteToPrint(char *format, ...)
{
va_list args;
va_start(args, format);
currentPositionPrint += vsprintf(latestPrint + currentPositionPrint, format, args);
va_end(args);
}
You can't use sprintf with variable arguments. You need to use vsprintf instead:
Change:
currentPositionPrint += sprintf(currentPositionPrint+latestPrint , format, args);
to:
currentPositionPrint += vsprintf(currentPositionPrint+latestPrint , format, args);
Free hint: use spaces between operators: foo += bar is more readable than foo+=bar.
#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);
}
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.)
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);
}