01-20-2013 12:06 AM
Does anybody have any suggestions for passing arrays of containers (C structs) between TS and c++ dll? I have exhausted my understanding here. I have noticed that when I create a type which is an array of containers (size=1), allow passing as a C struct, but exclude the container from passing as C struct, then the type shows up as a struct ref rather than an array in the C++ dll parameter dialog area. I was hoping I could exploit something here but no luck.
As a last resort, I could try to flatten the structures into an array of doubles, pass it as a VARIANT and reconstruct it on the other side - yuck! I have hundreds of different transfers to handle this way so I am still holding out hope for something better.
Solved! Go to Solution.
01-21-2013 09:29 AM
Are all of the elements in the array the same structure? If so, what you want to do is create a teststand data type that represents the structure of the element (not the array), and set all of the struct passing settings for all of the fields in the type appropriately (to match your C structure exactly). Then you can create an array of those as a variable in teststand and pass that to your C function.
Hope this helps,
-Doug
01-21-2013 12:36 PM
Hi dug9000,
I hear what you are saying, and after looking at it a bit more, it seems that the problem I am having is that the array (which only is 1 member of the toplevel C struct) may have variable length (including zero).
Here is a conceptual layout ot things.
//User type 1
struct Topic1 {
int a1;
int a2;
double a3;
}
//User type 2
struct Topic2 {
int size;
Topic1 array[size];
}
//User type 3
struct ComplexTopic {
int num;
Topic2 topic2;
}
It seems I have at least 2 questions here:
First, an array of size 0 makes no sense unless I can check for a 0 or NULL pointer, but TS seems to exclude zero sized arrays from structs, but what will it pass in its place? And how can I test for that?
Second, How can I change the array size? It seems that I might have to change the Type definition. Also I'm not sure how to set the "Store Struct As" and "Store Array As" fields to reflect my intentions.
Thanks,
Dan
01-21-2013 03:54 PM
In C/C++, I think if you define a struct with an array like this:
struct Topic2 {
int sizeVar;
Topic1 array[size];
}
Then the size is fixed. It can't really change because the compiler, whenever you allocate a variable of the type of the struct, has to allocate enough space to store all of the elements you declared in the struct definition. In otherwords sizeof(Topic2) includes the entire size of the array defined using the 'size' constant which must be a constant, not a variable. If you want something more dynamic, you would have to declare your structure as follows:
struct Topic2 {
int size;
Topic1 *array;
}
and you would have to dynamically allocate memory for the array pointer and dynamically free it when you are done with it.
One simpler approach you can take, if the range of size is pretty small, is to make the array as big as the max size you will ever need and add another member to tell you how many elements in the array are actually in use. And it seems like your struct def is close to that, but not quite right. For example, I'm pretty sure you can't use size for both the field variable and the array size. Instead you probably need something more like this
struct Topic2 {
int numElements;
Topic1 array[MAX_SIZE];
}
Hope this helps,
-Doug
01-21-2013 04:38 PM
Yes, I think your suggestion will work - very clever 😉
I would like to understand how things are done in TS however, so if I may pick your brain...
I will be auto-generating types, steps and sequences from interface definitions once I form a cohesive plan and would like the result to be intuitive and maintainable. Our testers will be creating test sequences using these "tools." Is it possible to handle this dynamically with TS? Perhaps with .net dll? Ascertaining the upper limits on array sizes may not be that easy to come by and I may need to choose a large number - which would create a lot of unnecessary data transfer. I would like to have reasonable performance.
I have noticed the "Pointer to Array" vs "Embedded Array" and "Pointer to Struct" vs "Embedded Struct" options in the Type Properties Dialog as well as the "Pointer to Element" vs Embedded Element" options in the C ++ dll Parameters Dialog - how are these used? Is there a way I can dynamically manage my memory? I would just like to better understand my options in TS.
Thanks for your help,
Dan
01-22-2013 10:02 AM - edited 01-22-2013 10:26 AM
Let me try to illustrate what the different settings mean:
Pointer to array:
struct ExampleStruct
{
int numElements;
ArrayType *ptrToArray
};
In this case the array is allocated by TestStand and cannot be allocated or deallocated by the called code module. The array still can't be empty, though really this could probably have been implemented in a way in which TestStand could pass NULL if the array was empty. but that's not how it currently works. If you use this setting the memory for the array will be dynamically allocated by TestStand so might be preferrable for that reason, but you would still have to have at least one element in the array on the TestStand side even if you aren't using it. The code module could just ignore the array anway if numElements == 0 so this might still be ok.
Embedded array:
struct ExampleStruct
{
int numElements;
ArrayType array[arraymaxsize]
};
In this case the elements of the array are actually part of the struct and not allocated separately.
Pointer To Struct:
struct ElementStruct
{
int somedata;
};
struct ExampleStruct
{
int numElements;
ElementStruct** ptrToArray
};
or
struct ExampleStruct
{
int numElements;
ExampleStruct* array[arraymaxsize]
};
In this case the elements are pointers to the struct rather than the struct directly.
Embedded Struct:
struct ElementStruct
{
int somedata;
};
struct ExampleStruct
{
int numElements;
ElementStruct* ptrToArray
};
or
struct ExampleStruct
{
int numElements;
ExampleStruct array[arraymaxsize]
};
In this case the elements are instances of the struct directly, rather than by pointer.
If you want the memory to be more dynamic because the max size for the array is unknown or can be quite big, you should use Pointer to Array. You still have to have at least one element, but you can just still an unused element in the array for the zero element case (I think, I haven't tried it recently, so I'm not 100% sure).
NOTE: I just looked at how this works more carefully. If you choose "Pointer To Array" rather than "Embedded Array" TestStand actually uses the size of the array from the parameter you pass (embedded array size is based on the size in the type). I think you still have to have at least one element though.
Hope this helps,
-Doug
01-22-2013 10:59 AM
Okay, I will experiment with these options.
Thanks Dug9000, you've been most helpful!