Fred chen Posted January 13, 2018 Report Posted January 13, 2018 (edited) Hi When I call the DLL, there is a structure: struct Signal { uint32 nStartBit; uint32 nLen; double nFactor; double nOffset; double nMin; double nMax; double nValue; uint64 nRawValue; bool is_signed; char unit[11]; char strName[66]; char strComment[201]; }; There is another Message structure to the above Signal: struct Message { uint32 nSignalCount; uint32 nID; uint8 nExtend; uint32 nSize; Signal vSignals[513]; char strName[66]; char strComment[201]; } The point is Signal vSignals[513]; I've tried to solve it like this,but the program will crash. How to create struct Message ,any good suggestions? Thanks a lot. message.vi Edited January 14, 2018 by Fred chen Quote
JKSH Posted January 15, 2018 Report Posted January 15, 2018 (edited) Hi, Your issue is related to data structure alignment and padding. See https://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member By default, C/C++ compilers add padding to structs to improve memory alignment. However, LabVIEW does not add padding to clusters. So, in your DLL, the structs' memory layout is probably like this: struct Signal { uint32 nStartBit; // 4 bytes uint32 nLen; // 4 bytes double nFactor; // 8 bytes double nOffset; // 8 bytes double nMin; // 8 bytes double nMax; // 8 bytes double nValue; // 8 bytes uint64 nRawValue; // 8 bytes bool is_signed; // 1 byte char unit[11]; // 11 bytes char strName[66]; // 66 bytes char strComment[201]; // 201 bytes // 1 byte (PADDING) }; // TOTAL: 336 bytes struct Message { uint32 nSignalCount; // 4 bytes uint32 nID; // 4 bytes uint8 nExtend; // 1 byte // 3 bytes (PADDING) uint32 nSize; // 4 bytes Signal vSignals[513]; // 172368 bytes (=513*336 bytes) char strName[66]; // 66 bytes char strComment[201]; // 201 bytes // 5 bytes (PADDING) }; // TOTAL: 172656 bytes There are two ways you can make your structs and clusters compatible: If you control the DLL source code and you can compile the DLL yourself, then you can update your code to pack the structs. If your compiler is Visual Studio, add #pragma pack(): https://msdn.microsoft.com/en-us/library/2e70t5y1.aspx If your compiler is MinGW, add __attribute__((__packed__)): https://stackoverflow.com/a/4306269/1144539 If you cannot compile the DLL yourself or if you don't want to change the DLL, then you can add padding to your LabVIEW clusters. Signal: Add 1 byte (U8) to the end of the cluster Message: Add 3 bytes in between nExtend and nSize. Add 5 bytes to the end of the cluster. I must say, the Message struct is huge! (>170 KiB) Edited January 15, 2018 by JKSH 1 Quote
Zyga Posted January 15, 2018 Report Posted January 15, 2018 Hi, I think you might want to read this paper. I am afraid that if you do not have access to the dll sources you will not be able to retrieve this data correctly. At the first place I would split up complex data into simpler types, then pass it to dll as separated arguments. That will make things easier in your dll code. Regards, Zyga Quote
ned Posted January 15, 2018 Report Posted January 15, 2018 Cross-posted here: https://forums.ni.com/t5/LabVIEW/Complex-cluster-array-with-static-size-in-calling-dll/m-p/3741685/ Quote
Fred chen Posted January 16, 2018 Author Report Posted January 16, 2018 Hi,JKSH,I really appreciate the information and advice you have given. I will try follow your advice that you have provided me. Quote
Fred chen Posted January 16, 2018 Author Report Posted January 16, 2018 5 hours ago, ned said: Cross-posted here: https://forums.ni.com/t5/LabVIEW/Complex-cluster-array-with-static-size-in-calling-dll/m-p/3741685/ Hi ned, Thank you very much for the reply, This is also the same day I wrote the post. Quote
JKSH Posted January 16, 2018 Report Posted January 16, 2018 You're welcome, Fred. I see on forums.ni.com that your code is a bit different. In particular, your Signal array has 512 elements instead of 513. Which is it? You need to count accurately, or else your program might crash. Also, nathand posted more important points at forums.ni.com: You must configure the the Array to Cluster node correctly Each Array to Cluster node can only handle up to 256 elements. So, you need to duplicate its output to reach 512/513 elements. Quote
Rolf Kalbermatter Posted January 16, 2018 Report Posted January 16, 2018 (edited) On 1/15/2018 at 9:02 AM, JKSH said: Hi, Your issue is related to data structure alignment and padding. See https://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member By default, C/C++ compilers add padding to structs to improve memory alignment. However, LabVIEW does not add padding to clusters. So, in your DLL, the structs' memory layout is probably like this: That is not quite true. LabVIEW for Windows 32 bit does indeed packed data structs. That is because when LabVIEW for Windows 3.1 was released, there were people wanting to run LabVIEW on computers with 4MB of memory , and 8MB of memory was considered a real workstation. Memory padding could make the difference between letting an application run in the limited memory available or crash! When releasing LabVIEW for Windows 95/NT memory was slightly more abundant but for compatibility reasons the packing of data structures was retained. No such thing happened for LabVIEW for Windows 64 bit and all the other LabVIEW versions such as Mac OSX and Linux 64 bit. LabVIEW on these platforms uses the default padding for these platforms, which is usually 8 byte or the elements own datasize, whatever is smaller. Quote struct Signal { uint32 nStartBit; // 4 bytes uint32 nLen; // 4 bytes double nFactor; // 8 bytes double nOffset; // 8 bytes double nMin; // 8 bytes double nMax; // 8 bytes double nValue; // 8 bytes uint64 nRawValue; // 8 bytes bool is_signed; // 1 byte char unit[11]; // 11 bytes char strName[66]; // 66 bytes char strComment[201]; // 201 bytes // 1 byte (PADDING) }; // TOTAL: 336 bytes struct Message { uint32 nSignalCount; // 4 bytes uint32 nID; // 4 bytes uint8 nExtend; // 1 byte // 3 bytes (PADDING) uint32 nSize; // 4 bytes Signal vSignals[513]; // 172368 bytes (=513*336 bytes) char strName[66]; // 66 bytes char strComment[201]; // 201 bytes // 5 bytes (PADDING) }; // TOTAL: 172656 bytes There are two ways you can make your structs and clusters compatible: If you control the DLL source code and you can compile the DLL yourself, then you can update your code to pack the structs. If your compiler is Visual Studio, add #pragma pack(): https://msdn.microsoft.com/en-us/library/2e70t5y1.aspx The correct thing to use for byte packed data is Quote #pragma pack(1) The following will reset the packing to the default setting, either the compiler default or whatever was given to the compiler as parameter (respectively what the project settings contain). #pragma pack() Quote If your compiler is MinGW, add __attribute__((__packed__)): https://stackoverflow.com/a/4306269/1144539 If you cannot compile the DLL yourself or if you don't want to change the DLL, then you can add padding to your LabVIEW clusters. Signal: Add 1 byte (U8) to the end of the cluster Message: Add 3 bytes in between nExtend and nSize. Add 5 bytes to the end of the cluster. I must say, the Message struct is huge! (>170 KiB) It sure is and I think trying to create this structure in LabVIEW may seem easier but is in fact a big pitta. I personally would simply create a byte array with the right size (plus some safety padding at the end and then create a VI to parse the information from the byte array after the DLL call. And if there would be more in terms of complicated data parameters for this DLL even create a wrapper DLL that translates between the C datatypes and more LabVIEW friendly datatypes. Edited January 16, 2018 by rolfk 1 Quote
JKSH Posted January 17, 2018 Report Posted January 17, 2018 13 hours ago, rolfk said: That is not quite true. LabVIEW for Windows 32 bit does indeed packed data structs. That is because when LabVIEW for Windows 3.1 was released, there were people wanting to run LabVIEW on computers with 4MB of memory , and 8MB of memory was considered a real workstation. Memory padding could make the difference between letting an application run in the limited memory available or crash! When releasing LabVIEW for Windows 95/NT memory was slightly more abundant but for compatibility reasons the packing of data structures was retained. No such thing happened for LabVIEW for Windows 64 bit and all the other LabVIEW versions such as Mac OSX and Linux 64 bit. LabVIEW on these platforms uses the default padding for these platforms, which is usually 8 byte or the elements own datasize, whatever is smaller. TIL! Thanks for the info, @rolfk Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.