I'm working on a program that generates an FDF file for filling in an Adobe PDF form. Currently, I have various procedures that are called, as before each one terminates, it opens the FDF file, writes its particular data, and closes the file.
I'm trying to put the code for writing the data to the FDF file in a separate procedure, and then have the other procedures call it. This would allow for a greater separation of the code by task, and if I had to change it in the future, I could do so easily.
I'm having some problems though, as I need to pass varying amounts of variables to fprintf. That is, I used to have a line like this:
fprintf(fp,"<</T(f1_44(0))/V(%d)>>\n",wages);
I wrote the below function, but I can't get it to work:
void writeToFDF(FILE *fp, char *filename, char *data, char *arg)
{
/* independent method for writing to FDF file */
/* open file */
fp=fopen(filename,"a");
fprintf(fp,data,arg);
/* close file */
fclose(fp);
}
So in theory, I would then in the parent function call:
writeToFDF(fp,"1040.fdf","<</T(f1_44(0))/V(%d)>>\n",wages);
I'm getting errors right now, and I believe it has to do with the last part of the function's arguments. Also, how can I get it to work if I have multiple arguments?
Thank you.
You need vfprintf. It will accept a variable list of arguments.
Like this:
void writeToFDF(FILE *fp, char *filename, char *data, ...)
{
va_list pl;
/* independent method for writing to FDF file */
/* open file */
fp=fopen(filename,"a");
va_start (pl, data);
vfprintf(fp,data,pl);
/* close file */
fclose(fp);
va_end(pl);
}
EDIT: while I tried to stay as close to your original code, ephemient's solution that omits the FILE *fp argument is in fact better: fp has only local significance (it's opened and closed in this function) so it should not be passed around.
This is what vfprintf is for.
#include <stdarg.h>
#include <stdio.h>
void writeToFDF(const char *filename, const char *format, ...) {
va_list ap;
FILE *fp = fopen(filename, "a");
va_begin(ap, format);
vfprintf(fp, format, ap);
va_end(ap);
fclose(fp);
}
You will need to use a Variadic function. See Forward an invocation of a variadic function in C
#include <stdio.h>
#include <stdarg.h>
void foo(FILE *file, char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(file, fmt, ap);
va_end(ap);
}
Related
I am trying to write a macro which gets the information and sends that information to another function by splitting the orginal va_list into string and another va_list spawned from the original one.
Below is my code.
Call to macro
/* Usage */
PRINT_LOG("Format log = %d, %f, %s", 1, 2.7, "Test");
My code below
/* my includes here */
#include <stdarg.h>
void printInfo(int level, const char *debugInfo, ...); /* defined in 3rd party API */
void formatLogs(int level, ...);
#define PRINT_LOG(...) formatLogs(0, __VA_ARGS__)
void formatLogs(int level, ...)
{
va_list args;
va_start(args, level);
/* get the first argument from va_list */
const char *debugString = va_arg(args, const char*);
/* here I want to get the rest of the variable args received from PRINT_LOG*/
va_list restOfArgs = ???????; /* restOfArgs should be 1, 2.7, "Test" */
/* Below I want to send the rest of the arguments */
printInfo(level, debugString, args);
va_end(args);
}
Is it possible to send some part of va_list as va_list to another function?? If so, how can i do it?
Thank you very much in advance.
The simplest thing to do, based on the code in your question, is to redefine the macro like so:
#define PRINT_LOG(s, ...) printInfo(0, s, __VA_ARGS__)
and just skip the intermediate function altogether. Because what you're trying to do can't be done like that.
The , ...) variable argument ellipsis is not a va_list. The variable arguments passed to a function aren't realized as a va_list until va_start is invoked. To pass a va_list as a function argument, the function has to have a va_list in its signature, like this:
int vprintf(const char *format, va_list argList);
I wrote a wrap function to replace the printf of stdio.h. I found that the wrap option worked on functions in stdlib.h, like malloc or exit. But it did not work on printf or fprintf.
Does the option wrap takes effects on functions in stdio.h ? And how can I wrap an arbitrary function ? I cannot get useful guide from the ld document.
Here is the code :
//gcc wrap.c -g -Wl,--wrap,fprintf
int __real_fprintf(FILE *stream, const char *format, ...);
int main(){
fprintf(stderr, "MAIN!\n");
return 0;
}
int __wrap_fprintf(FILE *stream, const char *format, ...){
__real_fprintf(stderr, "WRAP!\n");
return 0;
}
If you want this to work properly for fprintf, you need to also add the flag -fno-builtin-fprintf to the command line. Othwise, gcc will optimize the call to fprintf to instead call fwrite, and the linker will not see a call to fprintf to wrap.
In general, to properly wrap any function, you may need the corresponding -fno-builtin- option as well.
fprintf without arguments (other than the format string) is optimized to fwrite. Change your call of fprintf to fprintf(stderr, "%s\n", "MAIN!"); and the wrapping will take effect.
int __real_fprintf(FILE *stream, const char *format, ...);
int main(){
fprintf(stderr, "%s\n", "MAIN!");
return 0;
}
int __wrap_fprintf(FILE *stream, const char *format, ...){
__real_fprintf(stderr, "WRAP!\n");
return 0;
}
I would like everything that gets output to stdout to also be saved in a file in my C code. I know that I can do this by calling the process on the command line and piping it to a file:
myprogram.exe 1>logfile.txt
for example. But I am wondering if there is a way to do this from within the C code itself. Is there a function in the printf() family that can output to both the terminal and a specified file with the same arguments?
If not, what would be the syntax required to write my own printf()-style function which calls both printf() and fprintf() within it, using the same argument style as printf()?
Going off the suggestion to use variadic functions:
#include <stdio.h>
#include <stdarg.h>
/*
* Not all compilers provide va_copy(), but __va_copy() is a
* relatively common pre-C99 extension.
*/
#ifndef va_copy
#ifdef __va_copy
#define va_copy(dst, src) __va_copy((dst), (src))
#endif
#endif
#ifdef va_copy
#define HAVE_VACOPY 1
#endif
int
ftee(FILE *outfile, const char *format, ...)
{
int result;
va_list ap;
#if HAVE_VACOPY
va_list ap_copy;
#endif
va_start(ap, format);
#if HAVE_VACOPY
va_copy(ap_copy, ap);
result = vfprintf(outfile, format, ap_copy);
va_end(ap_copy);
if (result >= 0)
result = vprintf(format, ap);
#else
result = vfprintf(outfile, format, ap);
if (result >= 0) {
va_end(ap);
va_start(ap, outfile);
result = vprintf(format, ap);
}
#endif
va_end(ap);
return result;
}
That can be used like the standard fprintf function in that you specify an output file, except it will also write the normal output to stdout. I attempted to support relatively recent compilers that still didn't have a va_copy() macro (defined in C99) such as that which comes with Visual Studio 2012 (VS2013 finally has one). Some C runtimes also conditionally define va_copy() such that compiling with strict C89/C90 mode enabled will make it undefined while __va_copy() may remain defined.
You can use the fprintf() function, which is quite similar to printf() in the way it works.
Here is an example:
FILE *fp;
int var = 5;
fp = fopen("file_name.txt", "w");// "w" means that we are going to write on this file
fprintf(fp, "Writting to the file. This is an int variable: %d", var);
The output on your file would be this:
This is being written in the file. This is an int variable: 5
N.B: Opening the file using w as parameter will destroy the file's content every time you open it.
For writing to a file you have to use file operation commands, it is not possible to write to a file using printf (it prints only to the stdout). You can use:
sprintf(buf,"%d",var); //for storing in the buffer
printf(buf); //output to stdout
fputs(buf, fp); //output to file
I have a file pointer exported from a dll, which is initialized(fopen) by the application and then used(fprintf) inside the dll.
The problem is fprintf will throw an exception.
DLLFile.c
#define BUILD_FOO
#include "API.H"
File *pFile;
void exportedFunction()
{
fprintf(pFile,"This will result in an exception\n");//<-This print will crash
}
API.H
#ifdef BUILD_FOO
# define FOOAPI __declspec(dllexport)
#else
# define FOOAPI __declspec(dllimport)
#endif
FOOAPI extern File *pFile;
FOOAPI void exportedFunction();
APLICATION.C
#undef BUILD_FOO
#include "API.H"
void main()
{
pFile = fopen("path_to_folder","wt");
fprintf(pFile , "This print will work"); // <- This will be printed ok
exportedFunction();
}
1 From the debugging I've done, this is what I saw:
Inside the application, fopen() assigns for pFile an element from _iob[].
In the DLL when fprintf is called, it is checked that pFile is part of the _iob[], but the _iob[] from the application seems not to be the same with the one in the DLL(they have different addresses).
2 I have the same use case(with the same application) and another somewhat similar DLL, and everything works ok there(the _iob[] is at the same place in the application and DLL).
This is likely being caused by your application and your DLL disagreeing on which version of the C runtime they're using. Unless they're both compiled against the exact same version of the C runtime, all bets are off, and you can't call CRT functions from one using the data from another or vice-versa.
The safest way to avoid this problem is not to pass FILE* pointers across DLL boundaries. That way, any interaction with a FILE* will always happen using the same version of the CRT, and there's no danger of any mismatches. So your DLL should not expose a FILE* variable; instead it should be some opaque type, and all operations on the variable need to happen in the same module.
For example:
// API.h
FOOAPI void set_file(void *file);
FOOAPI void set_fprintf_callback(int (*my_fprintf)(void *, const char *, ...));
FOOAPI void exportedFunction();
// DLLFile.c
void *pFile; // Not exported
int (*fprintf_callback)(void *, const char *, ...); // Not exported
FOOAPI set_file(void *file)
{
pFile = file;
}
FOOAPI set_fprintf_callback(int (*my_fprintf)(void *, const char *, ...))
{
fprintf_callback = my_fprintf;
}
FOOAPI exportedFunction()
{
// Call back into the application to do the actual fprintf
fprintf_callback(pFile, "This should not crash");
}
// Application.c
int mydll_fprintf(void *pFile, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int result = vfprintf((FILE *)pFile, fmt, ap);
va_end(ap);
return result;
}
int main()
{
FILE *pFile = fopen(...);
set_file(pFile);
set_fprintf_callback(&mydll_fprintf);
exportedFunction();
return 0;
}
Have the application pass to the DLL a callback, and in that callback, have the application write to the file.
I'm looking to write what I would imagine is a fairly common macro. I want to emulate the repeated "-v" options on many POSIX programs by defining a bunch of macros of the following form:
#define V1(str, ...) if(optv >= 1){printf("%s: "str,prog,__VA_ARGS__);}
int main(int argc, char* argv[])
{
// ... stuff ...
int i = 1;
V1("This contains a variable: %d\n",i);
}
// Output:
// ./program: This contains a variable: 1
where optv counts the number of "-v" options found on the command line and prog contains the program name (neither shown). This works well, but the problem is that I have to use a variable. V1("Output") will generate a compiler error. I could always use V1("Output%s","") but there should be a cleaner solution.
The GNU C preprocessor has a special feature that lets you delete the trailing comma when there are no arguments filling the variadic portion by prepending the token-pasting operator ## to __VA_ARGS__:
#define V1(str, ...) if(optv < 1); else printf("%s: "str,prog, ## __VA_ARGS__)
Alternatively, if you wish to remain fully C99 compliant, you could incorporate the the format string parameter into the ellipsis, but in this instance you'll also need to refactor your code since you want to include the extra prog parameter between the format string and the varargs. Something like this might work:
#define V1(...) if(optv < 1); else myprintf(prog, __VA_ARGS__)
int myprintf(const char *prog, const char *fmt, ...)
{
// Print out the program name, then forward the rest onto printf
printf("%s: ", prog);
va_list ap;
va_start(ap, fmt);
int ret = vprintf(fmt, ap);
va_end(ap);
return ret;
}
Then, V1("Output") expands to myprintf(prog, "Output") without using any non-C99 compiler extensions.
EDIT
Also note that I inverted the if condition in the macro, due to some weird issues that can arise if you invoke the macro inside an if statement without braces—see this FAQ for a detailed explanation.
Why don't you use 2 different macros for each verbosity level; one which prints a message and variable, and one which just prints a message?
You should probably write yourself a small support function so that you can do the job cleanly:
extern void vb_print(const char *format, ...);
#define V1(...) do { if (optv >= 1) vb_print(__VA_ARGS__); } while (0)
I assume that both optv and prog are global variables. These would go into a header (you wouldn't write them out in the programs themselves, would you?).
The function can be:
#include <stdio.h>
#include <stdarg.h>
extern const char *prog;
void vb_print(const char *format, ...)
{
va_list args;
va_start(args, format);
printf("%s:", prog);
vprintf(format, args);
va_end(args);
}
There's no rocket science in there. You can tweak the system to your heart's content, allowing a choice of where the information is written, flushing the output, ensuring there's a newline at the end, etc.
Try this:
#define V1X(str, ...) if(optv >= 1) {printf("%s: "str,prog,__VA_ARGS__);} else
#define V1(...) V1X(__VA_ARGS__,0)
I believe that fixes the problem you described, and the else at the end fixed another problem.