I have a function
void foo(int cnt, va_list ap);
I need to use it, but requirement is quite strict, number of va_list vary and it will change during run-time. What I would like to do is:
create a va_list (which expects char*) form
QList<Contact*>
where Contact is a defined class
class Contact
{
public:
QString getName();
private:
QString m_name;
};
and I would like to populate in the loop va_list for example:
for (int idx = 0; idx<contacts.count(); idx++)
{
contacts.at(idx)->getName(); // this i would like to pass to va_list
}
Does anybody have a clue about how I could do this?
What you're wanting to do is to simulate the call stack so you can pass a constructed va_list to foo(). This is rather specific to the compiler ( and warning, there are differences between even 32- and 64-bit compilers ). The following code is for ENTERTAINMENT PURPOSES ONLY!!! as (if it even works on your system) it is prone to breakage. With it, I use a flat memory buffer and the populate it with a count and a bunch of character strings. You could fill it as appropriate with pointers to your strings and hand them down.
It does seem to work on my system, Windows 7 w/ Visual Studio 2008, for 32-bit applications only.
* BAD IDEA CODE FOLLOWS!!! *
#define PSEUDOSTACKSIZE ( sizeof(int) + 999 * sizeof(const char*) )
#pragma pack( push,1 )
union PSEUDOSTACK
{
int count;
char data[PSEUDOSTACKSIZE];
};
#pragma pack( pop )
void foo( int count, va_list args )
{
for ( int i = 0; i < count; i++ )
{
char *s = va_arg( args, char* );
printf( "%s\n", s);
}
}
void bar( PSEUDOSTACK data, ... )
{
va_list args;
va_start(args, data.count);
foo( data.count, args);
va_end(args);
}
// And later on, the actual test case code.
PSEUDOSTACK barData;
barData.count = 999;
char *p = barData.data + sizeof(int);
for ( int i = 0; i < 999; i++, p += sizeof(char*) )
{
*reinterpret_cast<char**>(p) = "ThisIsABadIdea";
}
bar( barData );
I'll now go hang my head in shame for thinking of such an idea.
...hmmm...maybe not portable...for sure not nice...but may solve yor problem...
va_list is (at least for visual c++) just a #define for char*
→ arguments don't need to be on the stack
→ arguments are just required to be continuous in memory
→ no need to use assembler and/or copying (see my 'just for fun answer' :-)
→ no need to worry about cleanup
efficient!
tested on w2k3 sp2 32bit + vc++ 2010
#include <stdarg.h>
#include <string>
#include <vector>
#include <iostream>
#define N 6 // test argument count
void foo(int n, va_list args);
int main(int, char*[])
{
std::vector<std::wstring> strings;
std::wstring s(L"a");
int i(0);
// create unique strings...
for (; i != N; ++i)
{
strings.push_back(s);
++s.front();
}
foo(N, reinterpret_cast<va_list>(strings.data()));
return 0;
}
void foo(int n, va_list args)
{
int i(0);
for (; i != n; ++i)
std::wcout << va_arg(args, std::wstring) << std::endl;
}
Your question is tagged C++ and there are nice ways (like streams) to avoid varargs completely in C++.
This is a great example of why va_args can cause pain. If you have any chance at all to change the signature of foo, that's your best option. Taking a std::vector<std::string> instead of va_list would just solve your problem right there.
If foo is in an external library you can't change, my next suggestion would be to find a different library.
If none of those is an option it seems like there ought to be a way to recursively build up the call list using va_list, but I couldn't figure out how to make that work.
If the number of elements in the list is limited, I would go for manual dispatch depending on the number of elements.
void call_foo(int count, ...) {
va_list args;
va_start(args, count);
foo(count, args);
va_end(args);
}
switch (contacts.count()) {
case 0: return call_foo(contacts.count());
case 1: return call_foo(contacts.count(),
contacts.at(0)->getName());
case 2: return call_foo(contacts.count(),
contacts.at(0)->getName(),
contacts.at(1)->getName());
case 3: return call_foo(contacts.count(),
contacts.at(0)->getName(),
contacts.at(1)->getName(),
contacts.at(2)->getName());
default: /* ERROR HERE, ADD MORE CASES */ return call_foo(0);
}
What you are trying to use is alloca. A va_list object can not store variables, the function call stores them, and you can only access it via va_list. These variables are only valid during the call, and they get ovverwriten afterwards.
THIS WILL NOT WORK:
va_list func(int dummy, ...)
{
va_list result;
va_start(result, dummy);
return result;
}
To allocate memory on the stack, without having to write a variadic functions use alloca. It works more or less like malloc, but you don't have to call free, it automagically frees itself when you leave the scope.
int * local = (int *) alloca(3 * sizeof(int));
local[0] = 10;
local[1] = 20;
local[2] = 30;
It's fundamentally the same as writing
int local[3];
local[0] = 10;
local[1] = 20;
local[2] = 30;
But with alloca 3 does not need to be a constant. Again you can only use it inside the enclosing scope, so do not return it from the function.
if what you want from a va_list is the multiple types in one list consider writing a union like this:
union variant
{
int i;
unsigned int u;
float f;
double d;
const char * s;
void * v;
};
It depends on compiler what is the va_list type, what are the va_start and va_end macros. You cannot do this in a standard way. You would have to use compiler-specific construction.
Maybe you can alter the 'foo' function? If so, then make it inversely - convert va_list to QList and make 'foo' accept QList.
// EDIT
Then see what the va_list type is, what the va_start and va_end macros are in your specific compiler. Then build your va_list in such a way that these macros will work on it.
<just for fun>
allowing arbitrary argument count
luckily sizeof(std::wstring) is a multiple of sizeof(int)
tested on w2k3 sp2 32bit + visual c++ 2010
#include <stdarg.h>
#include <string>
#include <vector>
#include <iostream>
#define N 6 // test argument count
void foo(int n, ...);
int main(int, char*[])
{
std::vector strings;
std::wstring s(L"a");
int i(0);
// create unique strings...
for (; i != N; ++i)
{
strings.push_back(s);
++s.front();
}
int n_stack_strings(N*sizeof(std::wstring)), // space needed for strings
n_stack(sizeof(int)+n_stack_strings); // overall stack space...needed for cleanup
__asm sub esp, n_stack_strings ; reserve stack space
std::wstring* p_stack(0);
__asm mov p_stack, esp ; get stack pointer
std::wstring* p(p_stack);
std::vector<std::wstring>::iterator string(strings.begin());
// copy to stack
for (; string != strings.end(); ++string, ++p)
new (p) std::wstring(*string);
__asm push N ; argument count...arguments right to left (__cdecl)
__asm call foo
// cleanup
for (p = p_stack; p != p_stack+N; ++p)
p->~basic_string();
__asm add esp, n_stack ; caller has to cleanup the stack (__cdecl)
return 0;
}
void foo(int n, ...)
{
int i(0);
va_list marker;
va_start(marker, n);
for (; i != n; ++i)
std::wcout << va_arg(marker, std::wstring) << std::endl;
va_end(marker);
}
</just for fun>
Related
I'm very new to C++ programming. I have a 3rd party app that can utilize Win32 DLLs. The test project I'm working on compiles without error, but in use doesn't seem to actually return the expected data.
With the below function Foo, the expectation is that the char array that is passed in will return the same values.
Instead, regardless of the data passed in my 3rd party app only sees the return value: 0
My suspicion is that I am not using the pointer 'char *data_out' correctly.
DemoLib.h:
#pragma once
#define DLL_EXP extern "C" __declspec(dllexport)
DLL_EXP void Foo(char* data_in, char *data_out);
DemoLib.cpp:
#include "stdafx.h"
#include "DemoLib.h"
#include <iostream>
DLL_EXP void Foo(char* data_in, char *data_out)
{
int a_size = sizeof(data_in) / sizeof(char);
std::string s_a = convertToString(data_in, a_size);
char strArray[100];
strcpy_s(strArray, s_a.c_str());
data_out = strArray;
}
std::string convertToString(char* a, int size)
{
int i;
std::string s = "";
for (i = 0; i < size; i++) {
s = s + a[i];
}
return s;
}
Exports.def:
LIBRARY DemoLib
EXPORTS
Foo #1
There are a couple of problems in your code. First, the line:
int a_size = sizeof(data_in) / sizeof(char);
will not give you the length of the data_in string! Rather, it will give you a (fixed) value that is the size of a pointer divided by the size of a char. So, assuming you have a C-style, null-terminated string, use this:
int a_size = int(strlen(data_in));
Second, your line:
data_out = strArray;
does not copy the string data from strArray to data_out! Rather, it simply replaces the pointer value (address) that data_out holds with the address of the (local) strArray array. (However, this will not change the value of any pointer in the calling module.)
What you need to do, here, is actually copy the data directly from the std::string into the string pointed to by the data_out argument (assuming it is a big enough buffer).
With these changes in mind, your Foo function could look like this:
DLL_EXP void Foo(char* data_in, char *data_out)
{
int a_size = int(strlen(data_in)); // Note: "strlen" returns a "size_t" (unsigned) type
std::string s_a = convertToString(data_in, a_size);
strcpy(data_out, s_a.c_str());
}
Alternatively, if you actually want the function to return a pointer to some local data, then you will: (a) need to declare that local data static; and (b) make the corresponding argument a pointer-to-pointer:
DLL_EXP void Foo(char* data_in, char** data_out)
{
int a_size = int(strlen(data_in)); // Note: "strlen" returns a "size_t" (unsigned) type
std::string s_a = convertToString(data_in, a_size);
static char strArray[100];
strcpy(strArray, s_a.c_str());
*data_out = strArray;
}
#include <cstdarg>
#include <iostream>
void print(const size_t n, ...) {
va_list args;
va_start(args, n);
for (size_t i = 0; i< n; ++i ) {
auto v = va_arg(args, uint64_t);
std::cout<< v << std::endl;
}
va_end(args);
return;
}
int main() {
print(6, 1,2,3,4,5,6);
//print(5, 1,2,3,4,5);
return 0;
};
then I got the output:
~/private/code/cpp/trial/ ./a.out
1
2
3
4
5
140728898420742
The problem is that your print function assumes that arguments are passed as uint64_t. When you invoke the function, you however specify the values as integer literals, so the compiler will choose to pass them as int.
If you pass the numbers as 1ULL, 2ULL etc. then things should work. Or assume that the values are of type int in function print. Note that this use of va_arg. The compiler will not warn about type mismatches and you can get pretty weird behavior. For example if by accident you pass a floating point value like 1.5.
Since you are using C++, variadic templates might be better suited to your case.
I have a C++ function to which I have to pass char* arguments[]. The prototype of this function is as follows:
void somefunc(char* arguments[])
To pass the above array to this function, I am generating this array from another function which can return me this char* array output, and this looks somehwhat like this.
char** genArgs(int numOfArgs,...)
{
va_list argList;
char** toRet = new char*[numOfArgs];
va_start (arguments, numOfArgs);
for(int cnt = 0; cnt < numOfArgs ; ++cnt)
toRet[cnt] = va_arg(argList, char*);
va_end(arguments);
}
I am confused how to actually write the above function correctly, given that I will be passing the inputs to function something like : genArgs(3, a.c_str(), b.c_str(), c.c_str()) or genArgs(2, a.c_str(), b.c_str())
How can I generate the above char* array without using char** (since this would have to be deleted before returning from the function to avoid memory leak).
From your declaration of genArgs, it seems that whenever you call genArgs, you know how many arguments you want to pass. Is this correct? If so (and if you are using C++11) then you can use std::array in the calling function. So instead of this:
char** arglist = genArgs (4, "MyArg1", mYaRG2", "LastArg", 0) ;
somefunc (arglist) ;
delete[] arglist ;
you can do it this way:
#include <array>
std::array<char*, 4> arglist { "MyArg1", mYaRG2", "LastArg", 0 } ;
somefunc (&arglist[0]) ;
But there is really nothing wrong with the first solution, unless you are a C++ ascetic. (However, you do need a return toRet ; statement in genArgs!)
this would have to be deleted before returning from the function to avoid memory leak
This is not entirely correct: although it is true that you need to eventually delete[] the pointer that you allocated with new[], you do not necessarily have to do it before exiting the function where the allocation happened.
You can do this:
// This allocates args; we now own the pointer
char **argsToPass = genArgs(2, a.c_str(), b.c_str());
// Make the call as usual
somefunc(argsToPass);
// Now that args are no longer needed, we delete them:
delete [] argsToPass;
The usual way would be to use an object that manages the lifetime of the array (such as a std::vector<char*> or a std::unique_ptr<char*[]>), and then to return that (so that the eventual release of the memory would be guaranteed by the type system):
std::vector<char*> genArgs(int numOfArgs,...)
{
std::vector<char*> toRet;
toRet.reserve(numOfArgs);
va_list argList;
va_start(argList, numOfArgs);
for(int cnt = 0; cnt < numOfArgs ; ++cnt) {
toRet.push_back(va_arg(argList, char*));
}
va_end(arguments);
return toRet;
}
To use this, do the following:
somefunc(&genArgs(3, a.c_str(), b.c_str(), c.c_str()).front());
I am passing an array to a function, and i am initializing it globally with some values.
I am using empty string in end of array to determine the array length.
Now, Is there some way to automatically initialize the array to have extra empty item in the end of it, so i have no chances to forget it from there? Just like the char[] works, it adds extra null to the end IIRC.
Here is my code what im using now:
struct twostrings {
string s1, s2;
};
twostrings options[] = {
{"text1", "more text1"},
{"text2", "more text2"},
{"text3", "more text3"},
{""}, // tells that the array ends here
}
int get_len(twostrings opt[]){
int p = 0;
while(1){
if(opt[p].s1 == ""){
return p;
}
p++;
// now here is a possibility to go in infinite loop if i forgot the empty string.
// currently i have a code here that checks if p > 10000 and gives error message to me if i manage to forget that empty string in accident.
}
return p;
}
void dosomething(twostrings options[]){
int len = get_len(options);
for(int p = 0; p < len; p++){
// do stuff
}
}
int main(){ // yes its not valid written main function. dont bother about it.
dosomething(options);
}
Passing around C arrays is not very idiomatic in C++. Try using a std::vector instead:
#include <vector>
#include <string>
struct twostrings {
std::string s1, s2;
};
typedef std::vector<twostrings> option_type;
twostrings options[] = {
{"text1", "more text1"},
{"text2", "more text2"},
{"text3", "more text3"}
};
int get_len(const option_type& options){
return options.size();
}
void dosomething(const option_type& options){
int len = get_len(options);
for(int p = 0; p < len; p++){
// do stuff
}
}
int main() { // This main function is perfectly fine!
option_type opt_vector(options, options + (sizeof options / sizeof options[0]));
dosomething(opt_vector);
}
Unforunately, you're not correct. The char array does not end automatically in a null, this is only a side effect of assigning it with a string literal (which has the automatic null at the end).
char x[] = "ABC"; // size 4, contains A, B, C, \0.
char x[] = {'A','B','C'}; // size 3, contains no terminating null.
So the short answer is no, there's no way to automatically end arrays with an automatic entry. There are a bunch of other options though, such as STL vectors which have other means of determining when you've reached the end. In C++0x there'll probably (IIRC) be a way to initialize the vector just like you'd like.
HTH.
EDIT:
Personally, I prefer to add the extra 0 at the end of the array myself, but I suppose there are ways to work around it using macros.
#define ARRAY(...) {__VA_ARGS__, {0}}
and use it like so
struct foo { char* x; char* y; }
struct foo x[] = ARRAY({"abc", "xyz"}, {"def","uvw"});
I have no idea if this works (and I have no preprocessor handy), and as I said, personally I don't like it. It also requires the first element in the struct to be something which can be assigned 0 to mark the end of the array.
Of course, this forces you to remember to wrap it in the macro call, which is pretty much as bad as forcing you to remember to terminate the array.
EDIT:
I just had a chance to test this and it works. Turns out variadic macros are, so far anyway, C only. However some (most?) C++ compilers support them anyway, a quick search turned up g++ and visual studio. Still I wouldn't favor this approach, I just added it for completeness.
Pass the length or the end instead of using a sentinel:
template<class T, int N>
int len(T (&)[N]) { // exists in a more general form as boost::size
return N;
}
typedef std::pair<std::string, std::string> twostrings;
// std::pairs have first and second members of the given types
void dosomething(twostrings options[], int size);
// call as: dosomething(array, len(array));
# or:
template<class T, int N>
T* end(T (&a)[N]) { // exists in a more general form as boost::end
return a + N;
}
void dosomething(twostrings* options_begin, twooptions* options_end);
// call as: dosomething(array, end(array));
// usage example:
void dosomething(twostrings* options_begin, twooptions* options_end) {
// you might name the parameters just 'begin' and 'end'
for (; options_begin != options_end; ++options_begin) {
// the 'begin' var advances through the entire sequence
// use for (twostrings* current = options_begin; current != options_end; ++current)
// if a separate copy is required
cout << options_begin->first << ": " << options_begin->second << '\n';
}
}
Note the [begin, end) iterator pattern (that's inclusive begin, exclusive end) is common in the stdlib (e.g. look at std::sort from <algorithm>).
This is a good halfway measure between arrays and containers such as std::vector, and allows you to keep the easy initialization syntax you have now (C++0x gives you that same syntax with containers such as std::vector, but 0x is not quite yet ready).
Don't use C style arrays in C++, they're just not worth the effort compared to vector.size(). You should use a boost::array<twostrings, length> for a static array.
Hell, you should probably just not use a static value.
There are better ways of finding array lengths. You can use:
1. sizeof(options) / sizeof(twostrings);
2. sizeof(options) / sizeof(options[0]);
3. std::vector<twostrings> options;
options.size();
4. ARRAYSIZE(options); (windows only)
Btw, if(opt[p].s1 == "") is checking 2 const char * pointers for equality, not 2 strings. Although compiller usualy optimizes equal string constants to point to one place, it is still an error.
You should use a NULL sentinell as it was adviced by Svisstack earlier.
edit: Proof
#include <stdio.h>
const char *one = "the string";
void main(){
const char *other = "the string";
printf("adress of 'one' = %x, it contains \"%s\"\n", one, one);
printf("adress of 'other' = %x, it contains \"%s\"\n", other, other);
if(one == other){
printf("one == other\n", one);
} else {
printf("one != other\n", one);
}
}
Output:
k:\temp>cl test.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86
/out:test.exe
test.obj
k:\temp>test.exe
adress of 'one' = 3d8140, it contains "the string"
adress of 'other' = 3d814c, it contains "the string"
one != other
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Are there gotchas using varargs with reference parameters
Hi, I have a problem with varargs.
Look at my code(Microsoft Visual Studio 2005 or 2008).
#include <stdarg.h>
struct Test { int a; };
void T1(int n, ...) {
va_list args;
va_start(args, n);
char* p = va_arg(args, char*);
va_end(args);
}
void T2(Test n, ...) {
va_list args;
va_start(args, n);
char* p = va_arg(args, char*);
va_end(args);
}
void T3(const Test& n, ...) {
va_list args;
va_start(args, n);
char* p = va_arg(args, char*); // p corrupt!!
va_end(args);
}
int _tmain(int argc, _TCHAR* argv[]) {
const Test t;
T1(1, "Test1");
T2(t, "Test2");
T3(t, "Test3");
return 0;
}
function T1, T2 work well. But T3 function have a problem. The pointer p doesn't point "Test3". Can't I use va_start with pass-by-reference?
Thanks in advance.
You cannot use references with va_start according to C++ Standard 18.7/3:
The restrictions that ISO C places on the second parameter to the va_start() macro in header
are different in this International Standard. The parameter parmN is the identifier of the
rightmost parameter in the variable parameter list of the function definition (the one just before the ...).
If the parameter parmN is declared with a function, array, or reference type, or with a type that is not compatible
with the type that results when passing an argument for which there is no parameter, the behavior is
undefined.
Short answer: no, you cannot do that.
NOTE: I saw the first answer which quotes the standard but I believe it is worth showing also my tests.
va_start is defined like this:
Visual 6: #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
Visual 8: #define _crt_va_start(ap,v) ( __va_start(&ap, _ADDRESSOF(v), _SLOTSIZEOF(v), \
__alignof(v), _ADDRESSOF(v)) )
With this code:
#include <cstdio>
int main()
{
char c;
char &rc = c;
int i;
int &ri = i;
printf("char ref:%d\n", sizeof(rc));
printf("int ref:%d\n", sizeof(ri));
return 0;
}
output
char ref:1
int ref:4
Since at implementation level references are passed on stack in a similar way to pointers this represents a problem since the size differs (it is because of the macro which computes the size of the type not taking into account that the parameter is actually a reference, which is not constant but depends on actual size of the type).