How to use parameters const char *format in custom printf - c

I'm looking for a function that print log information, in order to debug my program.
This function must look at a boolean and decide if write the log in a file or to the console.
int useFile;
int log_informations( ? )
{
if(useFile)
{
// open/close FILE *pf omitted
fprintf(pf, ? );
}
else
{
printf( ? );
}
return 0;
}
int main()
{
int answer = 42;
log_informations("The answer is %d.", answer);
return 0;
}
Can you help me with the parameter? I did not found any reference.
NB: In this question I made things clear and simpler as they were in my context, so I do not need workaround but, possibly, a simple answer.
Thank you in advance ;)

As other mentioned, you don't need to actually write a function. A macro could help here:
#define LOG(fmt, ...) fprintf(logToFile ? fileLogger : stdout, fmt, ##__VA_ARGS__)
To answer your question you can look at how printf and vprintf work:
int printf(const char *format, ...);
int vprintf(const char *format, va_list arg);
printf is a variadic function and you want to provide your own version that wraps vprintf and vfprintf.
#include <stdarg.h> // needed for va_list, va_start, and va_end.
int my_printf(const char *format, ...)
{
va_list ap;
int ret;
va_start(ap, format);
if (useFile) ret = vfprintf(pf, format, ap);
else ret = vprintf(format, ap);
va_end(ap);
return ret;
}
EDIT: as #phuclv mentioned, if you want to include file, line, and/or function information in your log a macro is the only way. For example, for appending file and line information you could do something like this:
#define LOG(fmt, ...) fprintf(logToFile ? fileLogger : stdout, __FILE__ ":" STRINGIFY(__LINE__) " " fmt, ##__VA_ARGS__)
#define STRINGIFY_HELPER(x) #x
#define STRINGIFY(x) STRINGIFY_HELPER(x)
You need STRINGIGY for __LINE__ because it is an int.

Related

Variadic Macro for custom print function with argument expansion in C

I am trying replicate the printf for my application. Instead of using stdout, I have a different set of user specific pointers that basically point to the location one wants to print something. So instead of having:
#define print(fmt, ...) printf(stdout, fmt, __VA_ARGS__)
I want something like this:
#define print(x, fmt, ...) dev_printf(x->pointer_to_a_screen, fmt, __VA_ARGS__)
Here the expectation is that the x is a struct that stores a users current context and information with it. I want to automatically expand x to use the pointer_to_a_screen which basically tells dev_printf where to print the given input. Expectation is the dev_printf needs to behave as any other standard printf function and the user can specify variable arguments.
Is this even possible? I keep getting a compile error for above #define print repeatedly and I cant understand why? I can't expand the first argument?
The trailing comma has to be removed in case no arguments are passed. Ie.
#define print(x, fmt, ...) dev_printf(x->pointer_to_a_screen, fmt, __VA_ARGS__)
print(something, "arg: %d", i);
// expands to dev_printf(something->pointer_to_a_screen, "arg: %d", i);
// all fine
// but:
print(something, "no arg");
// expands to dev_printf(something->pointer_to_a_screen, "not arg", );
// ^^
In your case you can just:
#define print(x, ...) dev_printf(x->pointer_to_a_screen, __VA_ARGS__)
Newer code should use __VA_OPT__:
#define print(x, fmt, ...) dev_printf(x->pointer_to_a_screen, fmt __VA_OPT__(,) __VA_ARGS__)
In days before __VA_OPT__ it was typical to use GNU extension ##__VA_ARGS__to:
#define print(x, fmt, ...) dev_printf(x->pointer_to_a_screen, fmt, ##__VA_ARGS__)
You can also use POSIX fopencookie to create a custom stream that you could manipulate with normal fprintf functions.
Each of standard *printf function have equivalent v*printf function. The best is to provide your own dev_vprintf function that would take a va_list and then provide a simple wrapper:
#ifdef __GNUC__
// ex. on gcc compiler this causes printf-like warnings to happen
__attribute__((__format__(__printf__, 2, 3)))
#endif
return_type print(some_type *x, const char *fmt, ...) {
va_list va;
va_start(va, fmt);
return_type e = dev_vprintf(x->pointer_to_a_screen, fmt, va);
va_end(va);
return e;
}
Such wrapper will check for type mismatches, is easy to maintain and it's easy to check for errors.
I would not use macro for that
int mystrangeprintf(MYTYPE *x, const char *fmt, ...)
{
int length;
char buff[256];
va_list va;
va_start(va, fmt);
length = vsnprintf(buff, sizeof(buff), fmt, va);
va_end(va);
dev_printString(x->pointer_to_a_screen, buff);
return length;
}

Create a printf function with custom prefix

I'm trying to create a printf function that print like this
[INFO] whatever 123
va_args works but I don't know how to add a prefix. At least the following code won't do
#include <stdio.h>
#include <stdarg.h>
void myprintf (char *fmt, ...)
{
va_list argp;
va_start (argp, fmt);
vfprintf (stdout, "[INFO] " fmt, argp);
va_end (argp);
}
int main (int argc , char **argv)
{
myprintf ("arg count is %d\n", argc);
return 0;
}
Any ideas?
"[INFO] " fmt
This code won't work. The "string pasting" behavior you're trying to use here is a preprocessor behavior, not a C operator. It can only be used on string constants -- not variables.
The easiest way of getting the behavior you want here will be to simply call printf twice:
printf("[INFO] ");
va_start(argp, fmt);
vfprintf(stdout, fmt, argp);
va_end(argp);
More difficult approaches which you may want to consider include:
Define myprintf() as a macro instead of a function so that it can use string pasting on the format argument.
Copy "[INFO] " and fmt into a temporary buffer and use that as a formatting string.
Copy "[INFO] " into a temporary buffer, use vsnprintf() to append the output to the buffer, then output that.

printf macro for compiler with and without support for VARIADIC

Please help me writing a printf macro for one compiler that supports VARIADIC and another that does not.
For instance:
#ifdef HAVE__VA_ARGS
printf macro
#else
printf macro
An solution with VARIADIC can be lock like this.
#define my_printf(_format, ...) { \
printf(_format, __VA_ARGS__); \
}
And if you really have an compiler without VARIADIC, then you have to implement an function with an variable argument list.
#include <stdarg.h>
#include <std.h>
int my_printf(const char *format, ...)
{
va_list ap;
va_start(ap, dst);
return vprintf(format, ap);
}

C puzzle...How Can I pass variadic arguments into a macro?

I got stuck here...
#include <stdio.h>
#define DBG_LVL(lvl, stmt) \
do{ \
if(lvl>1) printf stmt; \
}while(0)
#define DBG_INFO(stmt) DBG_LVL(1, stmt)
#define DBG_ERROR(stmt) DBG_LVL(2, stmt)
int main()
{
DBG_INFO(("hello, %s!\n", "world"));
DBG_ERROR(("crazy, %s!\n", "world"));
return 0;
}
As you can see, the code above uses macros like "DBG_INFO" or "DBG_ERROR" to control debug information level.
Now for some reason, I have to replace DBG_LVL() with a new function.
void myprint(int lvl, const char * format, ...);
The only difference is the debug level is taken as its fisrt parameter.
I was thinking:
#define DBG_LVL(lvl, stmt) myprint(lvl, stmt)
Of course it failed, because the "stmt" expression includes parentheses around.
Then I googled around trying to find a way to strip the parentheses, seems there's nothing could help.
I also tried some tricks to pass parameters into "stmt", still failed... :(
Can you help me?
# define EXPAND_ARGS(...) __VA_ARGS__
# define DBG_LVL(lvl, stmt) myprint(lvl, EXPAND_ARGS stmt);
Don't write this as a macro.
Write instead an ordinary varargs function:
void DBG_LVL(int level, char *fmt, ...)
{
if (level < 1) return;
va_list args;
va_start(args, fmt);
vaprintf(fmt, args);
va_end(args);
}
For myprint(), define a similar vamyprint(int lvl, const char *format, va_list ap) as well, and forward the same way.

Creating a proxy function to fprintf in an unobtrusive way?

I'd like to create a proxy to fprintf, like so:
void raise_exception(char *filename, int line, char *format_string, ...) {
fprintf(stderr, "Exception in `%s`:%d!\n", filename, line);
fprintf(stderr, format_string, ...);
exit(EXIT_FAILURE);
}
But what do I put in the place of the second ellipsis? Is it at all possible?
I'd like to simplify it even a bit more like so:
#define RAISE(...) raise_exception(__FILE__, __LINE__, ...)
But I don't think this would work either.
Any ideas? Thanks!
UPDATE
Straight from Wikipedia:
Variable-argument macros were introduced in the ISO/IEC 9899:1999 (C99)
So the define that would do it should look like so:
#define RAISE(...) raise_exception(__FILE__, __LINE__, __VA_ARGS__)
#include <stdarg.h>
void raise_exception(char *filename, int line, char *format_string, ...)
{
va_list args;
fprintf(stderr, "Exception in `%s`:%d!\n", filename, line);
va_start(args, format_string);
vfprintf(stderr, format_string, args);
va_end(args);
exit(EXIT_FAILURE);
}
Use vfprintf instead.
Please see this question:
Passing variable number of arguments around
Your exact example -- of wrapping printf -- is used as an example in the discussion here:
http://www.swig.org/Doc1.3/Varargs.html

Resources