07-31-2013 08:01 AM
Hello,
I am a bit strugling using LStrPrintf inside DLL.
I am passing a 2D string array, everything works OK, but when I try to access individual elements using LStrPrintf to copy the data from array string handles, I allways copy some garbage, because the handle has no null termination for its data. I tried to limit the copied data using standard printf arguments, but it has some limited functionality.
typedef struct { int32_t dimSize1; int32_t dimSize2; LStrHandle Strings[1]; } LVStringArray2D, **LVStrArrayHdl2D; //THIS WORKS and returns 0 int StrArrAllocPokus2D(LVStrArrayHdl2D StrArr, LStrHandle LVStringH, int32_t element) { return(int)LStrPrintf(LVStringH, (CStr)"%.1s", (*(*StrArr)->Strings[element])->str); } //THIS crashes on LStrPrintf (no return) int StrArrAllocPokus2D(LVStrArrayHdl2D StrArr, LStrHandle LVStringH, int32_t element) { return(int)LStrPrintf(LVStringH, (CStr)"%.*s", 1, (*(*StrArr)->Strings[element])->str); }
08-01-2013 07:31 AM
Hello,
I want to be clear about your problem: with the function written below "//THIS WORKS", you get no error and you succesfully copy one character from StrArr 2D string array to LVStringH,right? And when you use this:
int StrArrAllocPokus2D(LVStrArrayHdl2D StrArr, LStrHandle LVStringH, int32_t element) { return(int)LStrPrintf(LVStringH, (CStr) (*(*StrArr)->Strings[element])->str); }
you read nonvalid data? What is configuration of parameters in Call Library Function Node for these functions?
Some usefull links to this: http://zone.ni.com/reference/en-XX/help/371361J-01/lvexcode/printf/
and the overview of strings formats in attachment.
08-02-2013 04:25 AM
Thanks, thats a nice usefull link.
I used a workaround and convert the handle to Cstring first, after that I have no problem with garbage.
CStr buf = (CStr)calloc(sizeof(uChar), (*LVStringH)->cnt + 1); uint32_t err = LToCStrN((*LVStringH),buf,(*LVStringH)->cnt);
04-23-2025 01:23 PM - edited 04-23-2025 01:27 PM
The LStrPrintf and family of functions only support a subset of the modern C runtime library printf() format specifiers and some LabVIEW specific ones. Some of these use format specifiers that are nowadays used in C runtime library printf() for other parameters, such as %p being used there for pointers, while the LabVIEW variant uses it for Pascal strings.
LabVIEW's Printf family also doesn't support the * format in place of the field length.
A lot of these things has historical reason. At the time the LabVIEW functions were designed, C runtime library printf() was not only rather limited but also far from standardized across different platforms.The LabVIEW developers chose the basic standard specification at that time and extended it with their own ideas. The GNU folks of course eventually had other ideas and had no message about LabVIEW specific data types. Changing this now in LabVIEW is pretty much a non-starter because of many potential compatibility hazards with existing applications.
04-23-2025 05:31 PM - edited 04-23-2025 05:37 PM
OK, Rolf, you have really piqued my curiosity, and for two reasons:
1) what prompted you to reply to a decade-dormant thread (or did I miss something)?
2) what is this use of %p for Pascal strings about, which I've never encountered? I've only used it for SI formatting of numerics.
EDIT: disregard question #2, at least. I see now that you were referring to LabVIEW's PrintManager interface.
Best regards,
Dave
04-24-2025 02:35 AM - edited 04-24-2025 02:44 AM
Hi David
1) I was looking for information about the LabVIEW Printf function format specifier and came across this. Incidentally I was also hoping to find a way to use the * length specifier as modern printf() supports. Alas, no such thing in the LabVIEW functions and virtually zero chance that it will be ever added now.
2) No it has nothing to do with the PrintManager. LabVIEW internally uses in many places so called Pascal strings. Pascal was/is a programming language released in 1970 by Niklaus Wirth from the ETH Zürch, one of the two technical universities in Switzerland. It was heavily used in teaching computer science throughout the 80ies up until the 90ies. Pascal uses a different method to represent strings than C, by prepending the string with a byte that indicated the length of the string. That had the advantage that a string did not have to be scanned to determine its length, but the disadvantage was that strings were limited to 255 characters in length. MacOS was originally developed in Pascal too, which is the main reason that LabVIEW uses this string form in many places.
In the LabVIEW C interface extcode.h these strings are declared with the PStr typedef. It's similar to a LabVIEW string, which also sometimes gets called Long Pascal string, since it does not use a single byte to encode the string length but an int32 at the beginning of the buffer.
04-25-2025 01:53 PM
Circling back a little late. Thanks, Rolf, for the detailed reply!
I mis-titled the link in my prior post - the title should have been something like "Printf (LabVIEW Manager)", but my tired brain converted it wrongly to "PrintManager". However, the link leads to a good NI reference page relevant to the discussion. (Too late to edit the title of the link now.)
Yes, I've been around long enough to recall the heyday of Pascal, though I never really used it. So when I see a reference to a "Pascal string", or "p-string", I'm aware that it's a memory construct where the length is encoded at the head of the memory range. I've dissected so many arbitrary data structures in LabVIEW over the years using Flatten/Unflatten nodes, this is nearly second nature. But until now I hadn't really looked into the formatting specifiers for the LabVIEW internal printf variations to notice they provided formatting codes specific to Pascal strings. (For a brief moment when I read your first post I thought I had stumbled into undiscovered formatting codes useable by the "Format Into String" node!)
Enjoy the weekend!
Dave
04-26-2025 08:38 AM - edited 04-26-2025 08:43 AM
@DavidBoyd wrote:
Circling back a little late. Thanks, Rolf, for the detailed reply!
I mis-titled the link in my prior post - the title should have been something like "Printf (LabVIEW Manager)", but my tired brain converted it wrongly to "PrintManager". However, the link leads to a good NI reference page relevant to the discussion. (Too late to edit the title of the link now.)
Yes, I've been around long enough to recall the heyday of Pascal, though I never really used it. So when I see a reference to a "Pascal string", or "p-string", I'm aware that it's a memory construct where the length is encoded at the head of the memory range. I've dissected so many arbitrary data structures in LabVIEW over the years using Flatten/Unflatten nodes, this is nearly second nature. But until now I hadn't really looked into the formatting specifiers for the LabVIEW internal printf variations to notice they provided formatting codes specific to Pascal strings. (For a brief moment when I read your first post I thought I had stumbled into undiscovered formatting codes useable by the "Format Into String" node!)
Enjoy the weekend!
Dave
The Format into String (and Scan from String) while similar in how they work, are almost completely independent implementations inside LabVIEW from the Printf functions. Printf manager functions implement a version from before the original ANSI C (C89) standard of printf, but extended with LabVIEW specific datatypes.
Notable differences are
- the lack of a + sign before the field size to indicate to use a sign even if it is positive
- the lack of a space or # before the field size
- lack of the asterisk (*) character to indicate a field size or precision passed as extra integer parameter
- lack of i, n, p format specifiers (which were included in ANSI C but uncommon at that time in any compiler not explicitly claiming ANSI C standard conformance.
- only l as size specifier, meaning a 32-bit integer instead of the default 16-bit (ANSI C specifies that l means long, h means short and no specifier means int)
Undocumented but supported functionality:
- prepending the field size with zero, pads the number with 0 instead of spaces
Extra operand size indicators
- prepending the format specifier with {cc} indicates what specfic datatype the parameter has. cc is here one of the LabVIEW datatype codes such as iB, iW, iL, iQ, etc.
Extra format specifiers not in the ANSI version
- b Binary (Boolean)
- H LabVIEW string handle
- p Pascal String
- P LabVIEW Long Pascal String pointer (basically the one time dereferenced LabVIEW string handle)
- q Point (h and v coordinates)
- Q Point (h and v coordinates but formatted differently)
- r Rectangle
- R Rectangle differently formatted
- z LabVIEW path
The Format into String has many many more options, including timestamp formats, selectable decimal point, parameter index selection, etc. but lacks some of the more obscure LabVIEW specific format specifiers. For instance there is no need for a different specifier for a LabVIEW path. The Format into String function knows that it is passed a path so can perform the correct conversion from path to string when it encounters the %s specifier. and there are no multiple string types in a LabVIEW diagram, so no need to distinguish between a C string pointer, a LabVIEW handle or Pascal string.