This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I haven't been able to find an answer to the following question, and I am having some issues related to the functions.
My main programming is done in C#, and never really learned C++ while studying, but in my current job I have to do some C++ programming aswell.
Most of the C++ programming have been done by a former employee, and he made a function for logging.
Once in a while this function results in an error (Access Violation) - this is not shown to the user, but I see it while running the code through debugger.
When the error happens it points to this line of code:
vfprintf( LogFile, fmt, va );
I then took a closer look at the code before and after, and to put the above into a context the code around is:
void FileLog( char *fmt, ... )
{
va_list va;
struct time t;
struct date d;
long clk;
static int ReEntrant = 0;
if( FileLogEnabled == false )
return;
ReEntrant++;
if( ReEntrant > 1 )
return;
if( LogFile == NULL )
LogFile = fopen( LogFileName, "a+" );
if( LogFile != NULL )
{
gettime( &t );
getdate( &d );
fprintf( LogFile, "\n%d-%02d-%02d %2d:%02d:%02d.%02d0> ", d.da_year, d.da_mon, d.da_day, t.ti_hour, t.ti_min, t.ti_sec, t.ti_hund );
va_start( va, fmt );
vfprintf( LogFile, fmt, va );
va_end( va );
fflush( LogFile );
...
}
ReEntrant = 0;
}
Actually I dont understand why it is needed (and if it is?) call both fprintf and then vfprintf? I would think the first fprintf call would write the formatted string to the stream (File), and that would be enough?
A little explanation or some information would be much appreciated :)
EDIT: After the comment from nos - I tracked down the specific call to the function which today have often been causing this error.
FileLog( "TimerRestore[%d], Name=%s", Package.CurGame->Timers[ Index ].Name.c_str() );
I indeed think this could cause some trouble, as "TimerRestore[%d], Name=%s" should be followed by a decimal and string arguemtn, however only a string argument is given. I need to do some testing, but Im sure the author who wrote this code meant to write:
FileLog( "TimerRestore[%d], Name=%s", Index, Package.CurGame->Timers[ Index ].Name.c_str() );
However I still do not understand why the function call does not always seem to result in an error. Or maybe it is cause of the "ReEntrant" variable in FileLog function is blocking it when it does not fail?
Thanks a lot for all the feedback and information.
vprintf() (and friends) allow to use va_list as argument, which is useful when your function has a variable amount of arguments:
void log(FILE *file, const char* format, ... )
{
va_list args;
va_start (args, format);
fprintf(file, "%s: ", getTimestamp());
vfprintf (file, format, args);
va_end (args);
}
In your application you can call this function with a variable amount of arguments:
log(file, "i=%d\n", i); // 3 arguments
log(file, "x=%d, y=%d\n", x, y); // 4 arguments
I do not know why your function results in an error. Your code snippet does not provide enough details. The amount of type of provided function arguments might be the cause.
First off, using fprintf() and (especially) vfprintf() in C++ is evil.
To the point: fprintf() is a variadic function, it accepts an arbitrary number of arguments. Internally, variadic functions are implemented by "unpacking" the variadic arguments using va_list, va_start() and va_end().
vfprintf() is used when you want to access the functionality of fprintf() from your own variadic function after you've unpacked your own variadic arguments (that is, you have access to a va_list instance). vfprintf() is not variadic; it accepts a va_list storing the arguments.
You haven't posted the declaration of your function calling fprintf() and vfprintf(), but we can assume it's variadic. It first uses fprintf() to print some data into the LogFile, and then uses vfprintf() to print its own variadic arguments there.
vfprintf Allows you to have a variable argument list which means that you can create your list of parameters dynamically at runtime.
This is pretty common for logging. You want to make a printf-style log message like:
Log("The value of x is now %d", x);
But that requires variable arguments. So you need vfprintf. The reason fprintf is used as well is because it wants to write a date/time stamp and you can't add that extra stuff to the existing format passed to vfprintf.
Another way to do it is to use the string version vsprintf, and make one large string, then write it to file. But that's more prone to errors (like buffer overflow).
Related
I mean strings like "(%d%%%d) some text %s , %d%% %x %o %#x %#o \n". The printf family of functions somehow know how many args they would need from this string so separate argument for it is not needed. Is this functionality provided in c/c++ in terms of a separate function so I could write my own printf-like functions ? (yes I put these percents intentionally to accent how complicated it could get, so it is not simple counting of percent characters)
The problem with printf family is that it is not safe, and it doesn't really know or care how many format elements are there in string or in argument list.
printf family uses something called "variadic functions"; only one parameter is named (format string) and others are taken from the stack, without respecting their type or size - their type is deduced from format string, which makes it type-unsafe, and finds how many arguments to use by iterating over the string and finding all formatting specifiers, which makes it argument-number-unsafe. You can write variadic functions; syntax is
void foo(...);
and later you can use those macros and types, although if you are using C++, you should use C++11's variadic templates instead of C variadic functions, as variadic templates are type safe - you don't loose type information anywhere, and with universal references (but not quite thanks them) they are more powerful than variadic functions.
No, there is no standard library function for parsing printf-style format strings. If you want to write your own string formatting function, then I strongly recommend against following the printf example. It's inherently unsafe for the reasons mentioned in the others answers. It also has problems with localization since word order changes in some languages. Personally, I would write a type-safe function using templates and copying the .NET style of format strings. (Actually, I did do that--it's a lot of work but also fun.)
the printf family of functions only knows about one parameter, the first one...
It basically scans the string and each time it encounters a format specifier that it understands it pulls then next argument of that size from the argument list... this is an easily corruptible behavior.
imagine:
printf("%i",someInt); // fine
printf("%i",someLong); // depending on endianness and sized
// of those types could be the high or low 32 bits(probably)
printf("%i %i",someInt); // depending on abi could crash, read a int sized chunk
// of stack, or a register that would correspond to that
// parameter.
so inherently not safe..
you should pay attention to warnings and when writing portable code do things like:
size_t t = 5; //can be 32 or 64 bit depending on arch.
printf("%ull",(unsigned long long)t);
Edit. I guess I only half answered the question...
you can define your own variadic functions, the following adds count number of params and returns the result.
int sumList(int count, ...);
int main(int argc, const char * argv[])
{
printf("the answer is: %i",sumList(4,1,2,3,4));
return 0;
}
int sumList(int count, ...)
{
va_list args;
va_start(args, count);
int sum = 0;
for (int i = 0; i<count; i++) {
sum += va_arg(args, int);
}
va_end(args);
return sum;
}
I have been reading that some compilers support va_list with macros and users were able to overload the functionality with other macros in order to count the va_list.
With visual studio, is there a way to determine if the va_list is empty (aka count==0)? Basically I would like to know this condition:
extern void Foo(const char* psz, ...);
void Test()
{
Foo("My String"); // No params were passed
}
My initial thought was to do something like this:
va_list vaStart;
va_list vaEnd;
va_start(vaStart, psz);
va_end(vaEnd);
if (vaStart == vaEnd) ...
The problem is that va_end only sets the param to null.
#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap) ( ap = (va_list)0 )
I was thinking of maybe incorporating a terminator but I would want it to be hidden from the caller so that existing code doesnt need to be changed.
There is no way to tell how many arguments are passed through ..., nor what type they are. Variadic function parameters can only be used if you have some other way (e.g. a printf-style format string) to tell the function what to expect; and even then there is no way to validate the arguments.
C++11 provides type-safe variadic templates. I don't know whether your compiler supports these, or whether they would be appropriate for your problem.
I realize this question is fairly old, but I thought it might be helpful to flesh it out a bit. As Mike Seymour answered quite correctly, there is no absolutely reliable way to determine the number of arguments in a va_list. That's why the conventional way to define a variadic function is to include a parameter that has that information, like so: void func(const char *str, int count, ...);, which defines a contract your callers are supposed to abide by.
EDIT: The standard (7.16.1.1.3) is actually silent on the value returned by va_arg(vl, type) for any call past the end of the variable argument list. The most common case for most types is typed-zero. However, CAVEAT EMPTOR - it doesn't have to be.
The value returned from va_arg(vl, type) when there are no more arguments is a typed-zero value. For numeric types, it is 0. For pointers, it is a NULL pointer. For structs, it is a struct with all fields zeroed. If you elect to copy the va_list and try to count the copy, like so:
void func(const char *str, ...) {
va_list vl;
va_list vc;
int x;
int count;
count = 0;
va_start(vl, str);
va_copy(vc, vl);
do {
x = va_arg(vc, int);
if (x == 0) break;
count++;
} while (1)
va_end(vc);
.
.
. // do something, or something else,
. // based on the number of args in the list
.
va_end(vl);
You would have to make the assumption that the caller would abide by the contract not to pass a NULL or zero value in the list. Either way, you have to understand that the caller of a variadic function is responsible for abiding by the stated contract. So write your function, publish the contract, and sleep easy.
I am aware that my answer isn't an "orthodox" answer, however due to the limitation of the va_list macro, I found the following solution to work. We can look at a va_list as an array of chars, and even better, a null terminated one, so you can try
va_list argptr;
if(strcmp(argptr,""))
{
// not empty
}
else
{
// empty
}
I tried that and it worked for me.
I used Visual Studio 2013 Ultimate. The project type is Win32 Console Application. No compilation errors.
I have a function with following signature
char requestApiCall(int num, const wchar_t* pParams = 0, ...)
{
...
}
Now I want to to get all pParams in an array (or to be able to iterate over it). I know this is possible with some macros, but I have no idea how to do it.
Any help would be appreciated.
P.S. I'm using MinGW if it matters.
UPDATE
my question caused confusion. I will try to clarify (sorry for my grammar). Both Object Pascal and C# has the ability to pass unlimited amount of parameters to a method. In C# we achieve this with params keyword:
void Foo(params string[] strs)
{
...
}
Foo("first", "second", "another one", "etc");
I want to achieve same result in C++ without using any object/class. In my case, type safety is not a concern, but if there is a type safe way to achieve that goal, I will gladly hear your comments :)
Thanks
You need to look at the functions and macros declared in stdarg.h. Here is a tutorial that explains it.
http://publications.gbdirect.co.uk/c_book/chapter9/stdarg.html
I'm not sure what your function parameters are supposed to represent but I think you'll find that it needs to change.
By the way, I find that for C++ I can usually avoid variadic functions. This has the advantage of preserving type safety. Are you sure you really need a variadic function?
Using variadic function arguments is a dangerous and tricky business, and almost surely there is a better way - for example, you might pass an std::vector<std::wstring>& to your function!
OK, that said, here's how to use variadic arguments. The key point is that it is your responsibility to know the number and types of the arguments!
#include <cstdarg>
char requestApiCall(int num, const wchar_t* pParams, ...)
{
va_list ap; // the argument pointer
va_start(ap, pParams); // initialize it with the right-most named parameter
/** Perform magic -- YOU have to know how many arguments you are getting! **/
int a = va_arg(ap, int); // extract one int
double d = va_arg(ap, double) // one double
char * s = va_arg(ap, char*) // one char*
/* ... and so forth ... */
va_end(ap); // all done, clean up
}
Just for completeness, I would redefine the function as this:
char requestApiCall(std::vector<std::wstring> & params)
{
for (std::vector<std::wstring>::const_iterator it = params.begin(), end = params.end(); it != end; ++it)
{
// do something with *it
}
/* ... */
}
A good example of what you are trying to accomplish is the exec family of functions. exec() takes an variable list of arguments all of which are expected to be const char*. The last item is a NULL ((char*)0). The last item is the indicator for when the list of items is complete.
You can use the variadic macros in stdargs.h as others have described.
I have a logging function that takes in a variable number of arguments and uses _vsnprintf to format them. My problem is that when I debug my OCR automation the string it returns is sent to the log, so if the file said something like this:
This bitmap says %n
then it would get sent to my logging function like this:
void log(LPCSTR msg, ...)
{
char log[MAX_ALLOWED];
int length = sizeof(log) / sizeof(log[0]);
va_list argptr;
va_start( argptr, pzMsg );
// our msg accidentally has a %
if ( strchr(msg, '%') ) {
// debug assertion - no parameters were passed
_vsnprintf( log, length, msg, argptr );
}
log[length-1] = (char)0;
va_end( arg_ptr );
}
is there a way, along with the check for '%' that i can check if there were no arguments? thank you.
The traditional way to make sure something can't be expanded by printf is
log("%s", yourString);
Of course, you could also add a variant of log that only takes one argument, or you could count the number of variable arguments and not format the string if there aren't any.
If I understand you correctly, you would like to check the number of arguments actually passed to log().
Unfortunately, this is highly machine-specific. I know of only one architecture which provides an unambiguous argument count. That is the VAX. All the others depend on the caller and the callee to "get it right".
I'm trying to convert some code so that it compiles on gcc too (right now, it compiles only on MSVC).
The code I'm stuck at is in a pseudo-formatting function that accepts as input a format string and zero or more arguments (const char *format, ...). It will then process some of the placeholders consuming some of the arguments, and pass the rest to vsprintf along with a new va_list dynamically generated.
This is the actual code for generating the new va_list:
char *new_args = (char *) malloc(sum);
char *n = new_args;
for(int i = 0; i < nArgs; i++)
{
int j = order[i];
int len = _getlen(types[j]);
memcpy(n, args + cumulOffsets[j], len);
n += len;
}
vsprintf(buffer, sFormat.c_str(), new_args);
In my defense, I didn't and would never write this code. In fact, I think it's one of the most hackiest things I've seen in my whole life.
However, this function is very complex, very old, and very important. It's also hasn't been modified in years (well, except now) so while I'd like to rewrite it from scratch I can't justify the time it would take plus the bugs it would introduce.
So, I need a way to do this same thing on GCC.. But there a va_list is not a char * so I'm getting:
error: ISO C++ forbids casting to an array type '__va_list_tag [1]'
I'm a bit lost. Why do you need a new dynamically-generated va_list? Why not just reuse the old one?
I believe vsnprintf() uses a current va_list object (if you can call it that). So you are free to va_start(), use the arguments you want via va_arg(), then pass the remaining arguments via the va_list to vsnprintf(), and then call va_end().
Am I missing something? Why the deep copy?
And if you do need a deep copy, why not va_start() fresh, remove the arguments you want via va_arg(), and then pass the resulting va_list object to vsnprintf().
(Each call to va_arg modifies the va_list object so that the next call returns the next argument.)
Alternatively, you could just use va_copy(). (Though be sure to follow it with a corresponding va_end().)
Addendum: Also note that these va_ macros are based on C89 & C99 standards. GNU g++ will support them. Microsoft is somewhat more limited.
Following up on TonyK's comment:
What I said above works if you are pulling the first N items off the va_list. If you are pulling items out of the middle, that's harder.
There is no portable way to construct a va_list.
However, you could pull apart the format string, use it to determine the object types (double,float,int,etc), and print each one out individually with it's own format string (a subsection of the original format string). The multiple snprintf() calls will cause some overhead. But if this routine isn't called too often, it should be viable.
You could also print out subsections of the original format string with a suitably crafted va_list. In other words, the first vsnprintf() call prints elements 1..3, the second elements 5..7, the third 10..13, etc. (As vsnprintf() will ignore extra elements on the va_list beyond what it needs. You just need a series of corresponding format-string-fragments, and popping items off the va_list with va_arg() as needed for each vsnprintf() call.)
There's not enough context to figure out what you're trying to do here, but if you need to COPY a va_list, you may be able to use the C99 standard function va_copy, which gcc supports (but I have no idea if MS supports it).
There is a way to do this, it isn't pretty:
union {
char *pa;
va_list al;
} au;
....
au.pa = new_args;
vsprintf(buffer, sFormat.c_str(), au.al);
Using a union instead of a cast is ugly, but you can't cast if va_list is an array type.