How to print both to stdout and file in C - 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.)

Related

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.

Passing va_list to other functions

I have been trying to pass variable arguments to other function in C but it is producing inconsistent result in different runtime environment as well as in different runs in same environment:
int main()
{
int result = myprintf("Something \n %d", 9);
return result;
}
int myprintf(const char *format, ...){
printf("Something \n %d", 9);
printf("\n");
va_list args;
va_start(args, format);
int result = printf(format,args);
printf("\n");
va_end(args);
return result;
}
And the result produced is:
WWW.FIRMCODES.COM
9
WWW.FIRMCODES.COM
438656664
I could not find the reason for "438656664".
You cannot pass the variadic arguments to a variadic function. Instead, you must call a function that takes a va_list as argument. The standard library provides variants of printf and scanf that take a va_list; their names have the prefix v.
Your example should look like:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
int printfln(const char *format, ...)
{
int result;
va_list args;
va_start(args, format);
result = vprintf(format, args);
printf("\n");
va_end(args);
return result;
}
int main()
{
int result = printfln("Something \n %d", 9);
printf("(%d)\n", result);
return 0;
}
There are some gotchas, for example when you want to call two v... function for printing to the screen and a log file: The v... function may exhaust the va_list, so you must pass in a fresh one to each call if your code should be portable.
For the C++ fellow also reading this. You can actually do it using pack expansion without using vprintf.
This trick is quite handy when you need to wrap a method that takes the ellipsis (...)
and not a va_list.
For instance:
template <class ... Args>
void foo(const char *format, Args ... args)
{
printf(format, args...);
}
Here class ... Args is template parameter pack, Args ... args is function parameter pack, and args... is function parameter pack expansion.
Alternatively, you can simply use a wrapper macro:
#include <stdio.h>
#define myprintf(fmt, ...) ( printf("Something \n %d\n", 9), printf(fmt, __VA_ARGS__) )
int main (void)
{
int result = myprintf("Something \n %d\n", 9);
printf("%d\n", result);
}
Note the use of the comma operator to preserve the returned value of the right-hand printf call to the caller.
This isn't any less type safe than the (equally dangerous) stdarg.h variadic functions.
Just a simple demonstration and worked example with "a fresh one va_list" when you need to print/output-as-string a template string like constexpr const char* example = R"(template "%s")"; .
std::string print_templ(const char* format, ...)
{
va_list args1;
va_start(args1, format);
va_list args2;
va_copy(args2, args1);
std::vector<char> str(std::vsnprintf(nullptr, 0, format, args1) + 1);
va_end(args1);
const int ret = std::vsnprintf(str.data(), str.size(), format, args2);
va_end(args2);
return std::string(str.begin(), str.begin()+ret);
}

Duplicating a function with a new name

I am making a C library that creates a print function, which basically executes printf. Because of this, I wish to create a duplicate of printf from glibc, but with the name print. How can I duplicate this function without duplicating all of it's code?
(I found the code here but don't understand how to duplicate it in my library, or if it is legal to do so.)
There you go:
#include <stdarg.h>
void println(const char* format,...)
{
va_list args;
va_start(args,format);
vprintf(format,args);
printf("\n");
va_end(args);
}
You can use a variadic macro:
#define println(...) (printf(__VA_ARGS__), (void) puts(""))
You can either use a Macro:
#define print printf
or define a wrapper function
int print( char *fmt, ... )
{
va_list ap;
int n;
va_start(ap, fmt);
n = vprintf(fmt, ap);
va_end(ap);
return n;
}

How to redirect yyout to char* buffer in GNU flex?

By default yyout is set to stdout and can be redirected to FILE* stream. Is a way to redirect yyout to char*?
There are a number of ways to do it. If you post a bit of your scanner code where you are trying to use yyout may be I can give you a more specific answer:
Typically it's in your action where you'd do this. So instead of using ECHO or fprintf(yyout... you'd use something else like
<token> { snprintf(buf, sizeof(buf), "%s", yytext); }
earlier you'd have declared:
char buf[BUFSIZE];
addendum I - An alternate approach
There are clever ways of dealing with the situation, but they are prone to maintenance problems in the long run because they are "clever" .. .and the cleverer a solution the shorter its life. (unless the cleverness is well documented with caveats attached)
int yyprintf(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
if ( some_flag & FLAG_OUTFILE ) {
vfprintf(yyout, fmt, ap);
}
else {
sprintf(buf, fmt, ap);
}
va_end(ap);
}
where buf is a global buffer.
However if you want to make things a bit local:
Approach 2: Fine-grain control over where things go and when
You want fine grain control over where things go along the way. Sometimes you want output
to file, other times to a string, and you don't always know which is which and when and where you can use something like this:
int myvprintf(void *here, size_t len, const char *fmt, va_list ap)
__attribute__((format (gnu_printf, 3, 4), nonnull(1, 3))) {
int rv;
if ( len > 0 ) {
rv = vsnprintf((char *), len, fmt, ap);
}
else {
rv = vfprintf((FILE *)here, fmt, ap);
}
return rv;
}
int myprintf(void *here, size_t len, const char *fmt, ... )
__attribute__((format (gnu_printf, 3, 4), nonnull(1, 3))) {
int rv;
va_list ap;
va_start(ap, fmt);
rv = myvprintf(here, len, fmt, ap);
va_end(ap);
return rv;
}
and use myprintf along the way, you will have control over what is here all the time.
Just for Fun
Don't try this at home. But all yy* identifiers and ECHO are not plain variables, they are #define's. So you could do some clever macro rewriting:
For example, if you are using ECHO everywhere then you can redefine it to do whatever you like (just #undef and #define) in the top section:
%{
#undef ECHO
#define ECHO snprintf(buf, sizeof(buf), "%s", yytext)
%}
%%
<token> ECHO;
%%
just hide it all in convoluted headers and do other cleverness that will make debugging a hell later for a programmer you hate. This can have its own rewards and giggles.

C: Passing variable number of arguments from one function to another

So, here's a small problem I'm facing right now -> I'm trying to write a function that will accept a char* message and a variable number of arguments. My function will modify the message a little, and then It'll call printf with the message and given parameters. Essentialy, I'm trying to write something like that:
void modifyAndPrintMessage(char* message,...){
char* newMessage; //copy message.
//Here I'm modifying the newMessage to be printed,and then I'd like to print it.
//passed args won't be changed in any way.
printf(newMessage,...); //Of course, this won't work. Any ideas?
fflush(stdout);
}
So, anybody knows what should I do to make it happen? I'd be most grateful for any help :)
You want to use varargs...
void modifyAndPrintMessage( char* message, ... )
{
// do somehthing custom
va_list args;
va_start( args, message );
vprintf( newMessage, args );
va_end( args );
}
void modifyAndPrintMessage(char* message,...)
{ char newMessage[1024]; // **Make sure the buffer is large enough**
va_list args;
va_start(args, message);
vsnprintf(newMessage, message, args);
printf(newMessage);
fflush(stdout);
}
Use varargs to accept variable number of parameters then use sprintf to create the new message
You can use va_list from stdarg.h,
C example: http://www.tutorialspoint.com/cprogramming/c_variable_arguments.htm
C++ example: http://www.cprogramming.com/tutorial/lesson17.html.
An of course, see the man page: http://linux.die.net/man/3/stdarg
Man page example for reference:
#include <stdio.h>
#include <stdarg.h>
void
foo(char *fmt, ...)
{
va_list ap;
int d;
char c, *s;
va_start(ap, fmt);
while (*fmt)
switch (*fmt++) {
case 's': /* string */
s = va_arg(ap, char *);
printf("string %s\n", s);
break;
case 'd': /* int */
d = va_arg(ap, int);
printf("int %d\n", d);
break;
case 'c': /* char */
/* need a cast here since va_arg only
takes fully promoted types */
c = (char) va_arg(ap, int);
printf("char %c\n", c);
break;
}
va_end(ap);
}
There is a library which includes this functionality. Here is some example code from the reference:
#include <stdarg.h> /* va_list, va_start, va_arg, va_end */
int FindMax (int n, ...)
{
int i,val,largest;
va_list vl;
va_start(vl,n);
largest=va_arg(vl,int);
for (i=1;i<n;i++)
{
val=va_arg(vl,int);
largest=(largest>val)?largest:val;
}
va_end(vl);
return largest;
}
The ellipsis is actually valid code, and you can use the va_list object to parse a variable number of parameters.

Resources