I came across a function definition like:
char* abc(char *f, ...)
{
}
What do the three dots mean?
These type of functions are called variadic functions (Wikipedia link). They use ellipses (i.e., three dots) to indicate that there is a variable number of arguments that the function can process. One place you've probably used such functions (perhaps without realising) is with the various printf functions, for example (from the ISO standard):
int printf(const char * restrict format, ...);
The ellipses allow you to create functions where the number of parameters are not known beforehand, and you can use stdargs.h functions (va_start, va_arg and va_end) to get the specific arguments.
You do have to know the types of the arguments you extract and have some way of deciding when you're done. The printf functions do this with the format string (for both types and count), while my example code below always assumes const char * as the type with a sentinel value NULL to decide completion.
This link here has a good treatise on the use of variable argument lists in printf.
As an example, the following program contains a function outStrings(), that allows you to print an arbitrary number of strings:
#include <stdio.h>
#include <stdarg.h>
void outStrings(const char *strFirst, ...) {
// First argument handled specially.
printf("%s", strFirst);
va_list pArg;
va_start(pArg, strFirst);
// Just get and process each string until NULL given.
const char *strNext = va_arg(pArg, const char *);
while (strNext != NULL) {
printf("%s", strNext);
strNext = va_arg(pArg, const char *);
}
// Finalise processing.
va_end(pArg);
}
int main(void) {
char *name = "paxdiablo";
outStrings("Hello, ", name, ", I hope you're feeling well today.\n", NULL);
}
Wikipedia on vararg functions in C++.
They are called an elipsis and they mean that the function can take an indeterminate number of parameters. Your function can probably be called like this:
abc( "foo", 0 );
abc( "foo", "bar", 0 );
There needs to be a way of indicating the end of the list. This can be done by using the first parameter, as ion a printf(0 format string, or by a special terminator, zero in the example above.
Functions with a variable number of parameters are considered bad form in C++, as no type checking or user defined conversions can be performed on the parameters.
This is what is called a varargs function or a variable argument function in C.
One you'll probably recognise is printf.
Related
Old library was written in Delphi. Now I'm trying to write library in c++.
Below there is function in Delphi's library:
function MyFunction(Path:string; Options:PInteger; var Data: array of Byte):Integer; stdcall;
How should this function look in C++? Is below declariation right?
int __stdcall MyFunction(char* Path, int* Options, char* Data);
The big problem is the buffer. Your Delphi function passes an open array. This is implemented by passing both the array length, and the pointer to the first element. Your C++ translation does not do that. You'll need to pass an extra parameter specifying the length of the array.
Since you can expect that the function will not modify Path you would likely declare the first parameter as const char*.
So, the function would then look like this:
int __stdcall MyFunction(const char* Path, int* Options, size_t len, char* Data);
Now, if you are expecting that the function is to be binary interchangeable with the original C++ version you have a problem. You'd need to match the internal implementation of a Delphi open array. You can do that. The function would become:
int __stdcall MyFunction(const char* Path, int* Options, char* Data, int high);
Note that the length parameter appears after the pointer to the first element, and is named high. That's because a Delphi open array receives high(A) rather than Length(A).
You really must get out of the habit of passing Delphi specific types across interop boundaries.
Of course, I'm assuming here that you are still creating a library for interop and this function is at the interop boundary. If the function is internal then the declaration would perhaps be:
void MyFunction(const std::string &path, int &options,
const std::vector<char> &data);
There's no need for a return value since errors can be signalled with exceptions. Strings are stored in std::string, and a byte array in C++ is std::vector<char>.
TraceMessage is an WinAPI function with variable number of arguments. It is a tracing function, with a notation similar to printf, which generates a trace message in Windows tracing. The weird part here is that it receive a format string as part of the ellipsis, not as a dedicated argument.
It is possible to 'override' this function with a function of my own, which then needs to call TraceMessageVa (which is the same as TraceMessage, just with va_args rather than ellipsis).
So far so good; but now I want to access the traced message using a sprintf-like function, which has the format string out of the ellipsis. Thus I need to
- get the format string argument out of the ellipsis ;
- create a new va_list without the first argument.
Any idea about to how do it? Solutions specific to Visual Studio compiler are also acceptable. Thanks!
With a va_list you can pass it to a function which takes a va_list after having used va_arg on it already to have extracted one or more arguments. The va_list will then act like it "contains" only the rest of the arguments.
I have no experience with TraceMessage itself, but I've given an example using standard vprintf and a test function. You should be able to adapt as appropriate.
E.g.
#include <stdio.h>
#include <stdarg.h>
void test(int a, ...)
{
va_list va;
const char* x;
va_start(va, a);
x = va_arg(va, const char*);
vprintf(x, va);
va_end(va);
}
int main(void)
{
test(5, "%d\n", 6);
return 0;
}
I am trying to implement a variadic function. I searched the web and ended up finding out that most examples handle only one type of arguments (for example calculating average of many integers). Im my case the argument type is not fixed. It can either involve char*, int or both at the same time. Here is the code i ended up with :
void insertInto(int dummy, ... ) {
int i = dummy;
va_list marker;
va_start( marker, dummy ); /* Initialize variable arguments. */
while( i != -1 ) {
cout<<"arg "<<i<<endl;
/* Do something with i or c here */
i = va_arg( marker, int);
//c = va_arg( marker, char*);
}
va_end( marker ); /* Reset variable arguments. */
Now this would work okay if i only had to deal with integers but as you see i have a char* c variable in comments which i would like to use in case the argument is a char*.
So the question is, how do I handle the returned value of va_arg without knowing if it is an int or a char* ?
since you're doing c++ there's no need to use untyped C-style variadic function.
you can simply define a chainable method like
class Inserter
{
public:
Inserter& operator()( char const* s )
{
cout << s << endl;
return *this;
}
Inserter& operator()( int i )
{
cout << i << endl;
return *this;
}
};
then use like
Inserter()( "blah" )( 42 )( "duh" )
variant with templated insert operation commonly used for building strings.
cheers & hth.,
So the question is, how do I handle the returned value of va_arg without knowing if it is an int or a char* ?
You can't. There is absolutely no way to determine the type of a variadic argument. You have to specify it somewhere else. That's why functions like printf require you to give the type of the arguments in the format string:
printf("%s %i\n", "Hello", 123); // works
printf("%s %i\n", 123, "Hello"); // also valid (though most modern compiles will emit a warning), but will produce garbage or crash
You need some way of knowing. Consider how printf solves this, with a format string. It's not the only possible approach, but it's a well-known one.
From http://en.wikipedia.org/wiki/Variadic_function#Variadic_functions_in_C.2C_Objective-C.2C_C.2B.2B.2C_and_D:
In some other cases, for example
printf, the number and types of
arguments are figured out from a
format string. In both cases, this
depends on the programmer to actually
supply the correct information.
So, to handle multiple types, the insertInto() need a concept like format string.
You can make the processing conditional on the dummy parameter. I have routines that take an "action" argument and treats the arguments differently based on the action
For example:
int i; char *c;
switch(dummy) {
case 1:
i = va_arg(marker, int);
// do something with i
break;
case 2:
c = va_arg(market, char *);
// do something with c
break;
}
With the following code va_arg is returning garbage for the second and third pass through vProcessType.
// va_list_test.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <tchar.h>
#include <cstdarg>
#include <windows.h>
void processList(LPTSTR str, ...);
void vProcessList(LPTSTR str, va_list args);
void vProcessType(va_list args, int type);
int _tmain(int argc, _TCHAR* argv[])
{
LPTSTR a = TEXT("foobar");
int b = 1234;
LPTSTR c = TEXT("hello world");
processList(TEXT("foobar"), a, b, c);
return 0;
}
void processList(LPTSTR str, ...)
{
va_list args;
va_start(args, str);
vProcessList(str, args);
va_end(args);
}
void vProcessList(LPTSTR str, va_list args)
{
vProcessType(args, 1);
vProcessType(args, 2);
vProcessType(args, 1);
}
void vProcessType(va_list args, int type)
{
switch(type)
{
case 1:
{
LPTSTR str = va_arg(args, LPTSTR);
printf("%s", str);
}
break;
case 2:
{
int num = va_arg(args, int);
printf("%d", num);
}
break;
default:
break;
}
}
Is passing a va_list thing not allowed in this way? The first call to va_arg inside vProcessType returns the expected string. The second and third time through this function it returns a pointer to the start of the first string, instead of the values expected.
If I hoist the va_arg call to vProcessList, everything seems to work fine. It only seems when I pass a va_list through a function that I'm getting this behaviour.
You're passing the same va_list each time to vProcessType() - in each call to vProcessType() you're acting on the first va_arg in the list.
So you're always dealing with the TEXT("foobar") parameter when calling vProcessType().
Also note that the standard has this to say about passing a va_list to another function:
The object ap [of type va_list] may be passed as an argument to another function; if that function invokes the va_arg macro with parameter ap, the value of ap in the calling function is indeterminate and shall be passed to the va_end macro prior to any further reference to ap.
A foot note in the standard indicate that it's perfect OK to pass a pointer to a va_list, so what you might want to do is have vProcessType() take a pointer to the va_list:
void vProcessType(va_list* pargs, int type);
When you pass the va_list object to another function and that another function uses va_arg on the corresponding parameter, that va_list will have indeterminate value in the calling function when the control returns. The only thing you are allowed to do is to apply va_end to that va_list object.
This is how it is stated in the standard (7.15/3)
If access to the varying arguments is
desired, the called function shall
declare an object (generally referred
to as ap in this subclause) having
type va_list. The object ap may be
passed as an argument to another
function; if that function invokes the
va_arg macro with parameter ap, the
value of ap in the calling function is
indeterminate and shall be passed to
the va_end macro prior to any further
reference to ap.
Don't pass va_listobjects by value. If your intent is to continue argument parsing in each consequent sub-function, then you have to pass the va_list object by pointer.
If you really want to pass your va_list object by value, i.e. if you want each sub-function to parse from the same point, you have to manually copy your va_list object in advance by using the va_copy macro. ("In advance" means that you have to make as many copies as you'll need before any sub-function has a chance to do a va_arg on it.)
You're passing your va_list by value. Try passing a pointer to the one value instead (or if you wanted a C++ only version, you could use a reference):
void vProcessList(LPTSTR str, va_list args)
{
vProcessType(&args, 1);
vProcessType(&args, 2);
vProcessType(&args, 1);
}
void vProcessType(va_list *args, int type)
{
...
LPTSTR str = va_arg(*args, LPTSTR);
...
int num = va_arg(*args, int);
}
As others have noted, the C99 standard allows a portable (among C99 implementations) way for a program to run through a va_list more than once. There isn't any nice portable way to do that in pre-C99 implementations. What I did when I needed to run through a printf list more than once (for a "center string" function which had to evaluate the arguments once to determine how wide they would be, and then a second time to actually display them) was to examine the compiler vendor's "stdarg.h" and fudge my own implementation of the necessary functionality.
If one wanted a really portable implementation that would work on earlier C compilers, and if one knew in advance the maximum number of passes that would be required, I think one could create an array of va_ptr objects, use va_start on all of them, and then pass the array to the child routine. Sorta icky, though.
I came across a function definition like:
char* abc(char *f, ...)
{
}
What do the three dots mean?
These type of functions are called variadic functions (Wikipedia link). They use ellipses (i.e., three dots) to indicate that there is a variable number of arguments that the function can process. One place you've probably used such functions (perhaps without realising) is with the various printf functions, for example (from the ISO standard):
int printf(const char * restrict format, ...);
The ellipses allow you to create functions where the number of parameters are not known beforehand, and you can use stdargs.h functions (va_start, va_arg and va_end) to get the specific arguments.
You do have to know the types of the arguments you extract and have some way of deciding when you're done. The printf functions do this with the format string (for both types and count), while my example code below always assumes const char * as the type with a sentinel value NULL to decide completion.
This link here has a good treatise on the use of variable argument lists in printf.
As an example, the following program contains a function outStrings(), that allows you to print an arbitrary number of strings:
#include <stdio.h>
#include <stdarg.h>
void outStrings(const char *strFirst, ...) {
// First argument handled specially.
printf("%s", strFirst);
va_list pArg;
va_start(pArg, strFirst);
// Just get and process each string until NULL given.
const char *strNext = va_arg(pArg, const char *);
while (strNext != NULL) {
printf("%s", strNext);
strNext = va_arg(pArg, const char *);
}
// Finalise processing.
va_end(pArg);
}
int main(void) {
char *name = "paxdiablo";
outStrings("Hello, ", name, ", I hope you're feeling well today.\n", NULL);
}
Wikipedia on vararg functions in C++.
They are called an elipsis and they mean that the function can take an indeterminate number of parameters. Your function can probably be called like this:
abc( "foo", 0 );
abc( "foo", "bar", 0 );
There needs to be a way of indicating the end of the list. This can be done by using the first parameter, as ion a printf(0 format string, or by a special terminator, zero in the example above.
Functions with a variable number of parameters are considered bad form in C++, as no type checking or user defined conversions can be performed on the parameters.
This is what is called a varargs function or a variable argument function in C.
One you'll probably recognise is printf.