07-15-2004 11:47 AM
02-12-2016 01:58 AM
Hello folks,
Sorry for reviving this post, but WHAT IF the array of structs is of a fixed size, say '3'?
Ex:
struct myStruct
{
int x;
int y;
};
myStruct mS[3]; //I need 3 of these structures
void myFunc(myStruct *input)
{
input[0].x = 10;
input[1].y = 5;
input[2].x = 13; //just random assignments to test the functionality
}
Would this work in LabVIEW?
Thanks
Erick
02-12-2016 02:00 AM
Non related: Holy smokes just realized this post was ~12 years old!
02-12-2016 05:00 AM
@erickschmidt wrote:
Sorry for reviving this post, but WHAT IF the array of structs is of a fixed size, say '3'?
struct myStruct
{
int x;
int y;
};
myStruct mS[3]; //I need 3 of these structures
void myFunc(myStruct *input)
{
input[0].x = 10;
input[1].y = 5;
input[2].x = 13; //just random assignments to test the functionality
}
Basically, you need to allocate enough RAM for the data and let the function know where that is, which you do by generating the relevant data structure. I believe this can simply be a string of length N, or it can be an array of clusters of two I32s of size 3 or it can be a cluster with three sub-clusters. All are equivelent from the LV side, since they're all just a sequence of bytes. I believe that the correct number of bytes depends on the alignment on the C side, but I don't think there are any alignment issues with ints. If there are, I'm sure you'll find a post by Rolf or Nathan below this one in not too long.
The short version of that: yes, but you need to allocate the RAM. Just test it.
02-12-2016 07:16 AM
Basically what tst already said. A fixed size array of scalars or structs of scalars is always inlined and the LabVIEW equavalent is to place the element as many times into a cluster. This specific case, since all elements in the inner struct are of the same type you can also simply create an array of 3 * 2 int32 values and get the same memory wise.
02-12-2016 09:02 PM
Thank you both for your suggestions. (rolfk and tst (Knight of NI))
I was able to pass an array of clusters per your suggestions. I created the array before so that it resides in memory in LV, and then passed it as a Pointer to an Array to my DLL and modified the inputs by using input[0].x and input[2].y, etc for each different cluster in the array.
This guide here helped me quite a lot too:
https://decibel.ni.com/content/docs/DOC-9079
Cheers
02-16-2016 02:30 AM
Hello again,
I wanted to see if anyone can help me out. I have been reading extensively in the forum and on the documentation. I even thought I had it resolved but now I face another issue:
It seems the data cluster values are reversed or something's going on with the data type compatibility after passing through the DLL (through the Call Library Function Node).
I'd like to start by showing exactly what my code is for the DLL file:
#include "extcode.h"
static int example; //just testing a global variable
struct channel2
{
int32 a;
int32 b;
};
struct channel
{
double x;
int32 d;
double y;
int32 c;
struct channel2 z;
};
_declspec(dllexport) void CLUSTERSimple(struct channel *input);
_declspec(dllexport) void CLUSTERSimple2(struct channel *input);
_declspec(dllexport) void CLUSTERSimple(struct channel *input)
{
input->x += 1;
input->y += 2;
example = input->z.a;
}
_declspec(dllexport) void CLUSTERSimple2(struct channel *input)
{
input->z.b = example;
input->z.a = 100;
input->c = 33;
input->d = 44;
}
Specifically when I insert an int32 data type between the two doubles x & y in my struct, or if I place the int32 as the first value in the main structure, it kind of shows weird results. So as long as the int32 is after the doubles (i.e. double x, double y and THEN int32 c), it works. I don't know what's going on or if I'm missing something.
LabVIEW VI:
I used 'Adapt to Type' and 'Handles by Value' for both DLL Calls. I am currently using LabView 2013 (32-bit) on Windows 8.1 (64-bit).
I also verified that the order of the variables in the structure and sub-structure were correct, by using the "Reorder Controls in Cluster" option in LabVIEW. And I also set the variables data type as I32 for int32 and DBL for double, respectively (LV -> C).
As I mentioned before, If I remove the int32 d variable which is between the doubles, on both the DLL and the cluster, it works. Only when there's an int32 between the doubles or at the beginning of the structure, this happens. It seems the int32 is corrupting the next values?
Do I need to do something related to byte swapping or something like that that I might not be aware of (i.e. endianness compatibility issues)?
By the way, I can't afford a Wrapper or other sort of manual processing (such as "flattening" the structure to bytes or so) because this is just a sample program, but my actual application under development has a bunch of data types in the structure (around 55 variables) and I can't afford post-processing them since it translates to overhead.
Thanks Cheers!
02-16-2016 02:55 AM
You can see the c value to be a HUGE number so it seems its not detecting the appropriate data type or something. Also y is zero, and it shouldn't be.
Expected outputs:
Intermediate
x = 1 + 1 = 2
d = 2
y = 3 + 2 = 5
c = 4
z.a = 5
z.b = 6
(example = 5)
Final
x = 2
d = 44
y = 5
c = 33
z.a = 100
z.b = 5 (example)
Cheers
02-16-2016 02:57 AM
x and d are working fine, but AFTER d (which is the int32 in between the doubles) the results are all swapped or just strange.
Any clues?
02-16-2016 03:38 AM - edited 02-16-2016 03:53 AM
I suppose this is 32 bit LabVIEW. Read about structure element alignment in C!
LabVIEW 32 bit uses single byte aligned clusters. Microsoft Visual C and most other C compilers use 8 byte default alignment.
You need to put #pragma pack(1) and #pragma pack() around your structure definitions in your C file. However LabVIEW 64 bit switched to default byte alignment so doing it like this would cause trouble if you ever want to compile the code for both LabVIEW bitnesses.
Luckily NI provides two header files together with extcode.h called lv_prolog.h and lv_epilog.h. Put them around your struct declarations that you intend to interface on the diagram directly and you are ready, set and fine.
If you need to interface to existing code you have to decide if you ever might need to port the code to 64 bit LabVIEW or not. It's fairly easy to add dummy filler elements in your cluster to make it match the C compiler aligned struct. You simply have to make sure that every element starts at a multiple of the smaller of it's own size or the default alignment of the C compiler (8 bytes for Visual C). And it should not even make a difference between 32 bit and 64 bit DLLs unless a struct contains pointers of any kind.
A wrapper is the cleanest way but requires extra work to create and maintain, and unless there are other issues to crush like embedded pointers in structs or callback functions etc in your API it may be overkill.