05-10-2022 05:58 AM
one of the solution for the x64 was to create for each element in the array single variable in the struct but it didn't work on the LabVIEW x32.
for example for an array with a length of 32 you need to create 32 variable inside the cluster with the same type.
05-10-2022 06:35 AM
@LLindenbauer wrote:I also remember that. I recently had an array of char of size 32 inside a struct/cluster I dealt with in this way. It seems incredibly hacky and needlessly difficult to maintain. I guess writing wrapper functions that return LabVIEW-native types would be a cleaner solution. I'd enjoy hearing other solutions though.
One of the issues is that an Array is sent as a pointer and that works bad between systems. But a cluster has allocated space (or something like that).
05-10-2022 07:57 AM
@Yamaeda wrote:
Isn't a char[256] made as a 256 element u8 cluster? I have some memory of that being a solution in some old thread.
It is.
That's what I meant in the first reply: Re: dll with a complex type in a structure - NI Community:
wiebe@CARYA wrote:
So you can probably replace it with the right amount of integer data (e.g. a U8 for each element in the array). A LabVIEW array will always be a pointer.
05-10-2022 08:02 AM
@Yamaeda wrote:
@LLindenbauer wrote:I also remember that. I recently had an array of char of size 32 inside a struct/cluster I dealt with in this way. It seems incredibly hacky and needlessly difficult to maintain. I guess writing wrapper functions that return LabVIEW-native types would be a cleaner solution. I'd enjoy hearing other solutions though.
One of the issues is that an Array is sent as a pointer and that works bad between systems. But a cluster has allocated space (or something like that).
Of course you can also allocate data (in e.g. an array of U8s) and pass that.
In a way, that is the reverse solution.
Simply pass enough bytes in an array, matching the number of bytes in the cluster. The function doesn't know this memory is an array or a cluster... It will simply use the memory.
This array can than be unflattened to the cluster. You probably have to swap bytes, words and sometimes longs (for 64 bit integers).
05-10-2022 09:26 AM
wiebe@CARYA wrote:
@Yamaeda wrote:
@LLindenbauer wrote:I also remember that. I recently had an array of char of size 32 inside a struct/cluster I dealt with in this way. It seems incredibly hacky and needlessly difficult to maintain. I guess writing wrapper functions that return LabVIEW-native types would be a cleaner solution. I'd enjoy hearing other solutions though.
One of the issues is that an Array is sent as a pointer and that works bad between systems. But a cluster has allocated space (or something like that).
Of course you can also allocate data (in e.g. an array of U8s) and pass that.
In a way, that is the reverse solution.
Simply pass enough bytes in an array, matching the number of bytes in the cluster. The function doesn't know this memory is an array or a cluster... It will simply use the memory.
This array can than be unflattened to the cluster. You probably have to swap bytes, words and sometimes longs (for 64 bit integers).
Like this:
Option 1 and 3 work as char[10], the middle one needs work on the receiving part.
05-11-2022 05:47 AM - edited 05-11-2022 06:06 AM
@gmassaad1 wrote:
one of the solution for the x64 was to create for each element in the array single variable in the struct but it didn't work on the LabVIEW x32.
for example for an array with a length of 32 you need to create 32 variable inside the cluster with the same type.
If you interface to different architectures you have to be careful about alignment. A C compiler will usually not pack variables in a structure directly side by side, but will align each element on a natural border that is a multiple of the the smaller of its natural size and the currently used alignment. This alignment can be set globally through a command line option, or explicitly in the code though #pragma pack statements. If not specified in any of these locations the compiler uses a default alignment limit which is currently usually 8 for most compiler out there, but nowhere standardized so if a compiler chooses a different default, it is not breaking the standard. 😀
LabVIEW is a little special in that, since for the 32-bit Windows version it uses byte packing when allocating clusters and it passes that memory space also to Call Library Nodes. In all other still sold platforms including Windows 64-bit it uses 8 byte alignment. This byte packing anachronism is a remainder of the LabVIEW Windows 3.1 days. On computers where you only had 4 MB of RAM, it really could matter if you were continuously wasting memory by not packing clusters and the x86 architecture has a minimal performance penalty for unaligned memory access. Other architectures like the Sparc processor back in those days were going into overdrive when they had to access unaligned operands in memory and LabVIEW used already natural alignment on those platforms back in those days.
As far as the original problem goes, these are exactly equivalent in C in terms of memory used:
typedef struct
{
char buffer[256];
} Parameter;
void Function1(Parameter *param);
void Function2(char param[256]);
So in this specific case it would be simply enough to configure the according parameter in the Call Library Node as String, Pass as C pointer, and minimum size 256. The additional benefit of this would be that LabVIEW on return from the function will scan the string buffer for a NULL character and then resize its own string handle to that size, which usually is something you would really like to happen unless the string can contain embedded NULL characters. If that is the case you have to pass it as Array of U8, pass as Array C pointer, minimum size of 256 to prevent the Call Library Node from trying to scan for a NULL character.
If you pass it as a LabVIEW cluster of 256 U8 elements, there won't be any scanning for a NULL character either and you have to do yourself the conversion back into a string and find its length.