va_arg and dynamic memory allocation

I'm trying to use va_arg in a function that gets dynamically allocated (with new) float arrays. However, should I attempt to access these arrays, such as with
1
2
float* vector = va_arg( arglist, float* );
std::cout << vector[0];

the entire function fails (no error is given, but the program returns focus to the GUI, implying that the entire function had a forced return)

How does one solve this? Does it have to do with the fact that I used new instead of malloc? If so, is there a C++ equivalent to va_arg?

And yes, I am certain vector[0] is defined.
Last edited on
It doesn't matter how you allocate the space, you're passing pointers and trying to extract pointers.
Could you post the function?
C++ Equivalent to va_arg is just looking at the memory after the first variable. And that's what va_arg does anyway ;)
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
float* algLinComb( int count, ... ) 
{
    float* result = new float[4];
    result[0]=result[1]=result[2]=0;
    result[3]=1;
    va_list arglist;
    va_start( arglist, count );
    while( count-- )
    {
        real scalar = va_arg( arglist, real );
        float* vector = va_arg( arglist, float* );
        std::cout << *vector[0];// << vector[1] << vector[2] << vector[3];
        result[0] += *vector[0];//( scalar * vector[0] );
        //result[1] += ( scalar * vector[1] );
        //result[2] += ( scalar * vector[2] );
    }
    va_end( arglist );
    return result;
}


I've also recently had a problem with sscanf (http://cplusplus.com/forum/beginner/28995/) with the exact same symptoms.
You define scalar to be of the "real" class or struct, if this is not a POD, your program will terminate at run-time. I refer to this thread:
http://www.cplusplus.com/forum/beginner/28894/
Oh, sorry, real is simply a #define float real .
As well, that shouldn't matter, I'm trying to solve the problem with vector, not scalar

Actually, I've come up with a small, compilable code demonstrating my problem. If anyone could please try to do it on their own compilers, that would be much appreciated.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <iostream>

float* algLinComb( int count, ... ) 
{
    float* result = new float[4];
    result[0]=result[1]=result[2]=0;
    result[3]=1;
    va_list arglist;
    va_start( arglist, count );
    while( count-- )
    {
        float scalar = va_arg( arglist, float );
        float* vector = va_arg( arglist, float* );
        std::cout << vector[0];
    }
    va_end( arglist );
    return result;
}

int main()
{
    float* eye, *zAxis, *yAxis, *xAxis;
    eye = new float[4];
    zAxis = new float[4];
    yAxis = new float[4];
    xAxis = new float[4];
    for(int i=0;i<4;i++)
        zAxis[i]=yAxis[i]=xAxis[i]=eye[i]=(float)i;
    algLinComb( 4,
                                1.0, eye,
                                -2.0, zAxis,
                                -3.0, yAxis,
                                -4.0, xAxis );
    return 0;
}


It should give a run-time error on line 17.

And yeah, I didn't delete[] the memory, but that's hardly relevant.
Last edited on
1. http://www.cplusplus.com/forum/beginner/29009/#msg157100
2. Make your own remake of va_args to solve this issue. It's not that hard if you understand how vector stores its data and size ;)
So, from what I gather from that link, C++ doesn't allow variable-argument functions? That's silly.

And are you suggesting overrunning the buffer? In this particular case, I actually know that all float*'s sent will be of size 4, so could I simply overrun the buffer?

EDIT: As well, it should be mentioned that in that small code, not even scalar, which is a POD, is getting the correct value. It's simply being given a value of 0.
Last edited on
That link gathers that the Microsoft va_arg implementation doesn't support Variable Argument Lists with non-POD variables. C++ handles it fine.
Fair enough. However, given how I'm using Windows, the problem remains. Any hints?

I'm unsure as to how to "remake" va_args, given how each item given is not bundled into a vector and handed to the called function, but is sent individually. Thus, each item is not necessarily next to the other in the memory, correct?
When I said Windows I meant the stdarg.h file.

To make your own all you need is some pointers and the address of the first variable passed to your function. I'll give a quick example that does nothing but shows what I mean:
1
2
3
4
5
6
7
8
9
void VaArgs(unsigned int ArgCount, ...)
{
	char* Ptr = reinterpret_cast<char*>(&ArgCount);
	for(; ArgCount > 0; --ArgCount)
	{
		Ptr = reinterpret_cast<char*>(reinterpret_cast<unsigned int>(Ptr) + 4); //Not sure why there is spacing
		cout << short(*Ptr) << endl;
	}
}


Then if you call it like this:
1
2
3
4
VaArgs(3, 0, 1, 2);
Output:
0
1
2
Last edited on
You could use L B's code, which is, a quite nifty approach actually. It will still not work for non-POD's, though, as they can have different sizes (and you would have to send their sizeof() to the funtion aswell). But since variadic arguments are barely ever used (they seemed quite neat to me at first, but later I found they weren't too great), you might aswell just send a container (vector, list, queue, deque, map) to the function. It's a much safer way.
Why can't you use non-PODs with my method? You just need to know the structure of it and then you can find the variable that tells the size and loop through that.
Because a char pointer can contain only one byte of data. Furthermore, doing direct casts like that is not always safe. Using stl containers is more type-safe and potentially a lot faster.
Kyon wrote:
Because a char pointer can contain only one byte of data.
Who said it had to be a char pointer?? It was an example...
Last edited on
True, but you'd have to template it to make sure that it works with everything, with non POD's, a part of the "data" the pointer refers to is about their member functions, not just data member. Casting this can give strange results at times. As I said, STL containers are the way to go.
Topic archived. No new replies allowed.