I am writing a function, that takes a variadic argument list and produces a formated string from those. The problem is, that i use sprintf to create the string and i need to explicity list all paramaters, while programming
sprintf(string, format, a0, a1, a2, ...);
On cppreference however the description of sprintf says, that ...
... (additional arguments)
Depending on the format string, the function may expect a sequence of additional arguments, each containing a value to be used to replace
a format specifier in the format string (or a pointer to a storage
location, for n).
What i understand like, that i can store all the data to a pointer location and hand the pointer to sprintf.
int arr[X];
arr[0] = a0;
...
sprintf(string, format, &arr);
Trying that resulted in an unexpected behavior. Only numbers were written to the string.
Does it actually work that way and is there maybe a better solution?
My first attempt was to add each variadic argument separatly to the string, but that produced a lot of calls to sprintf, what i want to avoid.
Is it possible to pass the variadic argument list from one function to another?
Okay ... why did i not find this sooner...
The solution for me was to use vsnprintf instead of sprintf. That way one can pass the va_list to a formated string function and it is secure.
How to pass variable number of arguments to printf/sprintf
Related
The following piece of code works in C++ when running on Windows:
void* paramsList[MAX_PARAMS_NUM] = { 0 };
...some code to populate paramsList (p.s MAX_PARAMS_NUM is a constant)
vsnprintf((char*)pStr, MAXLEN, (char*)pTempFormat, (va_list)paramsList);
This code works fine on Windows, but i am trying to make it run on Linux and the program crushes because this conversion of paramsList to va_list doesn't work there.
Now the setting of this scenario is that i get a format string from a server that i don't control. The format string ('pTempFormat') is like the one used in printf of unknown number of % in it (maximum is MAX_PARAMS_NUM) and i populate the paramsList accordingly and then i use vsnprintf to create a string from the format string i got and the values populated in paramsList.(those values can be anything from integers, to hex to char * (aka strings) and any combination of them, according to the format string received from the server).
i don't know how many locations paramsList to pass to vsnprintf until i finish populating it according to the format string received from the server. So i need to somehow either pass a variable number of locations from paramsListto vsnprintf or to convert those locations into va_list (which i couldn't figure out how to do from what i read online).
I also considered using a combination of variadic templates and va_list - to somehow pass a variable number of locations from paramsListto a variadic function and to pass them on to vsnprintf. But i couldn't figure out how to pass certain locations from a given array to a variadic function either.
Update:
I use Visual Studio 2015 to compile on Windows, and GCC 4.9 on Ubuntu.
The error i am getting when trying to compile this code on Linux is: error: ISO C++ forbids casting to an array type 'va_list {aka __va_list_tag [1]}'
va_list is an unspecified type. That means it may be a void* [] or something else entirely.
That it worked by chance in some cases is just that va_list is compatible with void* [] on one particular platform for one compiler, it is by no means indication that this is legal.
The correct way to deal with this is, unfortunately, to stop using the printf family and parse the format string yourself, there is no standard functionality to reach in and fetch the parsed format string to use for yourself.
I have a c++ program, I would like the first argument of the main (argv[1]) to correspond to a table of float. Is it possible to do that??
I was thinking about putting in a string my floats separated with spaces (e.g. "1.12 3.23 4.32 1.1 ...")
Is there a way to automatically convert such a string into a table of floats? If I understand well the atof function converts a string into a double. So it seems it could be possible to split my string using the spaces and then convert each portion using atof.
This option does not seem to be very efficient to me? In addition it returns double and not float :(
So, is there a better way to pass table of float as argument of a c++ program ?
Thank you
A stringstream can do both the splitting at spaces and the parsing into a float.
std::stringstream ss(the_string);
std::vector<float> v(std::istream_iterator<float>(ss),
(std::istream_iterator<float>()));
// the extra parentheses here are ugly but necessary :(
How to obtain the string with the data depends on how large it is and where it is supposed to come from. Just keep in mind that in many systems the arguments passed to program are already split by spaces, putting each part in a different element of argv.
Save it in a text file, and then read it from the file when your program starts. I isn't worth it to pass it as a command-line argument.
The main() parameter list is as it is. You can pass the strings of your numbers as arguments to your program. The main function will have to parse its argument.
When you want to pass a space separated list of numbers in argv[1] you can use the strtok function to get the individual number strings and have to pass it to a conversion function.
When your conversion function returns a double you should check that the result can be represented by a float and cast the value to a float variable. But I would consider to use double as the internal representation.
In addition to Singer's answer:
The commandline should be used mainly by human, not computer. If you really need a table of values, use configuration file. You can always use human readable format for it.
According to what I read about the va_arg macro, it that retrieves the next argument pointed by the argument list. Is there any way to choose the index of the argument I want to get, like an array index?
For example I need to do an operation where I need to call at least 3 times the va_arg macro but I want those 3 times to retrieve the same argument and not the next one on the list. One solution could be using a function and passing the argument, but I don't want that.
Also if there is no other macros able to do this, how can I reference to the start of the array arguments by a pointer? I know its not portable and not type safe, etc, etc. Just for the sake of learning.
Here is an example code of how i want to implement it:
bool SQLBase::BindQuery (char* query, int NumArgs, ...)
{
va_list argList;
va_start(argList, NumArgs);
SQLPrepare (hstmt, query, SQL_NTS);
for (int x = 0; x < NumArgs; x++)
{
SQLBindParameter (hstmt, (x+1), GetTypeParameter (va_arg(argList, SQLPOINTER*), SQL_C_CHAR, SQL_CHAR, 10, 0, va_arg(argList, SQLPOINTER*), va_arg(argList, SQLLEN), &recvsize[x]);
}
The va_arg is called 3 times for the SQLBindParameter function and i want the first 2 times to point to the same argument, not increasing the count member on the argument list.
First of all, calling va_arg multiple times in your function invocation is hairy, since you don't know in which order these calls happen. You need to do this beforehand, so your arguments are retrieved in the correct order.
Second, no: there is no array-style usage auf va_list. This is because va_list doesn't know a thing about the arguments on the stack; you are supplying the type in your va_arg calls, and va_arg can then increase the (internal/conceptual) pointer contained in the va_list because it knows the size of that argument. Getting to the third argument would require you to supply the types of the first two.
If all the arguments are the same size (like "void*") you can always just make a loop that calls va_arg the appropiate number of times. This is "kind of" portable if you can be reasonably sure that your arguments are in fact the same size. I'm not too confident that doing this would be the best course of action, though -- the need to do it might indicate that a different setup would be more appropiate, like passing an array in the first place instead of using a variable argument function.
You can also just take the address of a function argument and assume they are on the stack in some order. This is horribly unportable since you need to know about calling conventions which can vary between compilers, and may even change based on compilation options. I would definitely advise to NOT do something like this.
what is the best way to call a function with the following declaration
string Extract(const char* pattern,const char* input);
i use
string str=Extract("something","input text");
is there a problem with this usage
should i use the following
char pattern[]="something";
char input[]="input";
//or use pointers with new operator and copy then free?
the both works but i like the first one but i want to know the best practice.
A literal string (e.g. "something") works just fine as a const char* argument to a function call.
The first method, i.e. passing them literally in, is usually preferable.
There are occasions though where you don't want your strings hard-coded into the text. In some ways you can say that, a bit like magic numbers, they are magic words / phrases. So you prefer to use constant identifier to store the values and pass those in instead.
This would happen often when:
1. a word has a special meaning, and is passed in many times in the code to have that meaning.
or
2. the word may be cryptic in some way and a constant identifier may be more descriptive
Unless you plain to have duplicates of the same strings, or alter those strings, I'm a fan of the first way (passing the literals directly), it means less dotting about code to find what the parameters actually are, it also means less work in passing parameters.
Seeing as this is tagged for C++, passing the literals directly allows you to easily switch the function parameters to std::string with little effort.
I'm using transform algorithm and std::toupper to achieve this, but can this be done in one line, like this ?
transform(s.begin(), s.end(), ostream_iterator<string>(cout, "\n"),std::toupper);
I get error on this, so do I have to make a unary function for this and call it with transform or I can use some adaptors ?
Use ostream_iterator<char> instead of ostream_iterator<string>:
transform(s.begin(),s.end(),ostream_iterator<char>(cout,"\n"),std::toupper);
std::transform transforms each character and pass it to the output iterator. That is why the type argument of the output iterator should be char instead of std::string.
By the way, each character will be printed on a newline. Is that what you want? If not, don't pass "\n".
--
Note : You may have to use ::toupper instead of std::toupper.
See these
http://www.ideone.com/x6FB5 (each character on a newline)
http://www.ideone.com/RcEKn (all characters on the same line)
First, if you want to output chars (and all of the chars), you'll
need to use ostreambuf_iterator<char>, and not
ostream_iterator<string>. And ostreambuf_iterator<char> expresses
better what you want than ostream_iterator<char>; you're
outputting chars directly, not formatting anything.
(ostream_iterator uses the << operator, which formats.)
Second, be aware that there is not always a one to one translation of
lower to upper (e.g. 'ß' maps to the two character sequence "SS" in
upper case), so std::transform can't really be used to do the job
correctly. (And of course, it doesn't handle multibyte encodings like
UTF-8 correctly.) For all but the simplest uses, you need something
more complicated. But even for the simplest cases:
std::toupper is overloaded: one of the overloads is a template, which
takes two arguments, and the other is a function which takes a single
int; neither will work directly here, and the fact that transform is
also a template means that overload resolution and template type
deduction won't work even if they did. So basically, you have to add
something. It's possible to use the 2 argument template function if you
add enough qualifiers and use boost::bind or something similar to bind
the second argument, but it's almost as much text as writing a simple
toupper functional argument your self. And you can't use the single
argument form (which can be unambiguously accessed if you include
<ctype.h> and use ::toupper) because it has undefined behavior if
you use a char as the argument when you call it: you have to convert
the char to unsigned char first (unless, of course, plain char is
unsigned in the implementation you are using—and in all
implementations to which your code will ever be ported).