Developer Center Resources

cancel
Showing results for 
Search instead for 
Did you mean: 

Dereferencing Pointers from C/C++ DLLs in LabVIEW

» Calling External Code » Calling C/C++ DLLs » Dereferencing Pointers

Overview

Many C/C++ functions return data in the form as a pointer (or reference) to the memory address that holds the actual data. Programmers get the value at the memory address by ‘dereferencing’ the pointer. However, since LabVIEW hides memory management from the user, LabVIEW users need another mechanism to ‘dereference’ the pointer.

 

Note: Some simple data types like numerics and simple structs can automatically be dereferenced in the Call Library Function Node itself. For details, refer to the section titled Receiving Pointers and Automatically Dereferencing in Passing and Receiving Pointers with C/C++ DLLs from LabVIEW.

 

There are two ways that LabVIEW offers to dereference pointers:

  • MoveBlock function: Low level, more control, can handle any data types
  • GetValueByPointer function: Easier, adapts to data type, does not handle certain complex types

     

Option 1: MoveBlock Function

MoveBlock  is a Memory Manager Function that takes a memory address and returns the data at that memory address. The MoveBlock function allows you to control how many bytes to read as well as the datatype to convert the data to. Because of its low level control, you can in essence dereference any type of data, from simple numerics to complex structs that contain arrays of structs within it.

 

To call MoveBlock:

  1. Open up the Block Diagram 
  2. Drop a Call Library Function Node
    (Function Palette » Connectivity » Libraries & Executables » Call Library Function Node) 
  3. In the Library Name or Path field, enter LabVIEW 
  4. This will populate the Function name field 
  5. Pick MoveBlock from the Function name dropdown box  

    010MoveBlockPickFunction.png
  6. Switch to the Parameters tab 
  7. Set up the parameters as follows:
    Name Type Data Type / Format Pass
    Return Type Void    
    Address (Pointer) Numeric Signed Pointer-Sized Integer Value
    Destination Adapt to Type <Depends on Data>  
    Size Numeric Signed Pointer-Sized Integer Value


    address_pass.png


  8. Click OK

 

In order to use MoveBlock, wire in the pointer to the Address input, a constant/control of the same data type as the value being dereferenced to Destination, and the size of the data type (in bytes) to Size.

 

For instance, to dereference a 32-bit integer, your Block Diagram would look as follows:

030DereferencingAnInteger.png

 

Note: In order to dereference pointers to pointers (for example a 2-D array, or an array of strings), you would have to

Option 2: GetValueByPointer VI

GetValueByPointer is a VI that encapsulates some of the complexity of using MoveBlock and will automatically adjust its operation based on the data type wired to it. While it is simpler to use, it does not automatically dereference arrays or structs (clusters) that contain arrays. Elements in arrays need to be dereferenced individually.

040GetValueByPointerHelp.png

 

The GetValueByPointer VI can be located at:
<LabVIEW>\vi.lib\Utility\importsl\GetValueByPointer\GetValueByPointer.xnode

 

To use the VI, wire in the pointer to Pointer, a constant/control of the same data type as the value being dereferenced to InputType.

 

For instance, to dereference a 32-bit integer, your Block Diagram would look as follows:

050GetValueByPointerSnippet.png

 

Special Case: Dereferencing Arrays

Array variables in C/C++ are actually pointers that point to the first element of the array. Because of this, when a function returns an array, it is really returning a pointer to the array. To dereference a pointer to an array you can use either MoveBlock or GetValueByPointer.

 

For example, to dereference a pointer to an array of 32-bit integers:

060DerefArrayOfInt_MoveBlock.png

065DerefArrayOfInt_GetValueByPointer.png

Special Case: Dereferencing Strings

Strings in C/C++ are actually arrays of type char. So string variables are really pointers to the first character in the string. Because of this, when a function returns a string, it is really returning a pointer to the string. To dereference a pointer to a string you can use either MoveBlock or GetValueByPointer, however it is easier to use GetValueByPointer as you do not need to know the length of the string beforehand.

 

For example, to dereference a pointer to a string:

070DerefString_GetValueByPointer.png

Special Case: 2D Arrays

2D arrays are represented as an array of arrays. Since an array is really a pointer, a 2D array is a pointer to an array of pointers, where each pointer points to the individual rows of the array.

802DArray.png

 

So in order to dereference a 2D Array, you must first dereference the individual pointers to each row, and then dereference in individual elements in each row. The following snippet shows an example of this:

0802dArrayInMemory.png

 

Conclusions / Next Steps

You have seen two methods to dereference pointers in LabVIEW. The GetValueByPointer VI is simpler to use, however has limitations with automatically handling arrays and structs with arrays. The MoveBlock function is lower level and allows you full control over dereferencing pointers, however is slightly more complex to use.

 

To see examples of both methods in use, refer to:

Calling C/C++ DLLs Containing Simple and Complex Datatypes from LabVIEW

Jervin Justin
NI TestStand Product Manager
Comments
rolfk
Knight of NI Knight of NI
Knight of NI
on

I think an enhancement might be at its place here for 2D arrays. The shown syntax in the picture might be a bit misleading, since an array allocated in C as

float array[6][6]

is not really an array of pointers but simply a pointer to a memory block containing 6 * 6 elements. It is also how LabVIEW treats arrays, as a single contiguous block of memory containing all the elements.

C is a bit ambiguous about multidimensional arrays, as there does not really exist a clear syntax that distinguishes the single block multi dimensional array and the array of pointers. It's the choice of the implementer how he wants to represent multi dimensional arrays in memory, and a user of such a function has to comply to that choice.

Rolf Kalbermatter
My Blog
nathand
Proven Zealot
Proven Zealot
on

The MoveBlock example is confusing and incorrect. The address parameter should be passed by value, not by pointer, since the user already has the address value on a wire (returned from a DLL, presumably).

Philippe_RSA
Member
Member
on

Excellent, thank you.

This MoveBlock function appears to be the answer to extract data from a .net function (array pointer output)

How do I send a pointer to a .net function, (array pointer input)? is it the same MoveBlock function? but how do I use it?

nathand
Proven Zealot
Proven Zealot
on

This question would be better posed on the forum, after a search there to see if your question has already been answered. Please add more details in your post, including any documentation of the .NET interface you're using. It is unusual to pass a raw pointer to a .NET component; it would be more common to pass a .NET array. There are posts on the forum explaning how to create a .NET array in LabVIEW and pass it to an external component.

RVallieu
Active Participant
Active Participant
on

Hmm.  The MoveBlock setup does not seem to be available on Linux Desktop installed LabVIEW. LV2019 64-bit on CentOS 7.6

 

Is there another library that should be entered in the path field on Linux?

 

EDIT:

Seems like I can manually type in MoveBlock and configure the parameters and LabVIEW does not throw an error when I close the configuration dialog and return to the block diagram.  I guess the function auto populate just doesn't work.  Will need to test it with some code I suppose.

Ryan Vallieu CLA, CLED
Senior Systems Analyst II
NASA Ames Research Center