Data Conversion

When to Convert Manually

Under most conditions, MATLAB® software automatically converts data passed to and from external library functions to the data type expected by the external function. However, you may choose, at times, to convert some of your argument data manually. Circumstances under which you might find this advantageous are:

Primitive Types

The shared library interface supports all standard scalar C data types. The following tables show these C types with their equivalent MATLAB types. MATLAB uses the type from the right column for arguments having the C type shown in the left column.

The second table shows extended MATLAB types in the right column. These are instances of the MATLAB lib.pointer class rather than standard MATLAB types. See Creating References for information on the lib.pointer class.

MATLAB® Primitive Types

C TypeEquivalent MATLAB Type

char, byte

int8

unsigned char, byte

uint8

short

int16

unsigned short

uint16

int

int32

long (32-bit)

int32

long (64-bit)

int64

unsigned int, unsigned long

uint32

float

single

double

double

char *

cstring (1xn char array)

*char[]

cell array of strings

MATLAB® Extended Types

C TypeEquivalent MATLAB Type

integer pointer types (int *)

(u)int(size)Ptr

Null-terminated string passed by value

cstring

Null-terminated string passed by reference (from a libpointer only)

stringPtr

Array of pointers to strings (or one **char)

stringPtrPtr

Matrix of signed bytes

int8Ptr

float *

singlePtr

double *

doublePtr

mxArray *

MATLAB array

void *

voidPtr

void **

voidPtrPtr

type **

Same as typePtr with an added Ptr (e.g., double **
is doublePtrPtr)

Converting to Other Primitive Types

For primitive types, MATLAB automatically converts any argument to the data type expected by the external function. This means that you can pass a double to a function that expects to receive a byte (8-bit integer) and MATLAB does the conversion for you.

For example, the C function shown here takes arguments that are of types short, int, and double:

double addMixedTypes(short x, int y, double z)
{
   return (x + y + z);
}

You can simply pass all of the arguments as type double from MATLAB. MATLAB determines what type of data is expected for each argument and performs the appropriate conversions. For example, type:

calllib('shrlibsample', 'addMixedTypes', 127, 33000, pi)

MATLAB displays:

ans =
  3.3130e+004

Converting to a Reference

MATLAB also automatically converts an argument passed by value into an argument passed by reference when the external function prototype defines the argument as a reference. So a MATLAB double argument passed to a function that expects double * is converted to a double reference by MATLAB.

addDoubleRef is a C function that takes an argument of type double *:

double addDoubleRef(double x, double *y, double z)
{
    return (x + *y + z);
}

Call the function with three arguments of type double, and MATLAB handles the conversion:

calllib('shrlibsample', 'addDoubleRef', 1.78, 5.42, 13.3)

MATLAB displays:

ans =
   20.5000

Strings

For arguments that require char *, you can pass a MATLAB string (i.e., character array).

For example, the following C function takes a char * input argument:

char* stringToUpper(char *input) {
   char *p = input;

   if (p != NULL)
      while (*p!=0)
         *p++ = toupper(*p);
   return input;
}

libfunctions shows that you can use a MATLAB cstring for this input.

libfunctions shrlibsample -full
          .
          .
   [cstring, cstring] stringToUpper(cstring)

Create a MATLAB character array, str, and pass it as the input argument:

str = 'This was a Mixed Case string';
calllib('shrlibsample', 'stringToUpper', str)

MATLAB displays:

ans =
   THIS WAS A MIXED CASE STRING

Enumerated Types

For arguments defined as C enumerated types, you can pass either the enumeration string or its integer equivalent.

The readEnum function from the shrlibsample library returns the enumeration string that matches the argument passed in. Here is the Enum1 definition and the readEnum function in C:

enum Enum1 {en1 = 1, en2, en4 = 4} TEnum1;

char* readEnum(TEnum1 val) {
   switch (val) {
   case 1 :return "You chose en1";
   case 2: return "You chose en2";
   case 4: return "You chose en4";
   default : return "enum not defined";
   }
}

In MATLAB, you can express an enumerated type as either the enumeration string or its equivalent numeric value. The TEnum1 definition above declares enumeration en4 to be equal to 4. Call readEnum first with a string:

calllib('shrlibsample', 'readEnum', 'en4')

MATLAB displays:

ans =
   You chose en4

Now call it with the equivalent numeric argument, 4:

calllib('shrlibsample', 'readEnum', 4)

MATLAB displays:

ans =
   You chose en4

Structures

For library functions that take structure arguments, you need to pass structures that have field names that are the same as those in the structure definitions in the library. To determine the names and also the data types of structure fields, you can:

When you create and initialize the structure, you do not necessarily have to match the data types of numeric fields. MATLAB converts to the correct numeric type for you when you make the call using the calllib function.

Finding Field Names of a Structure

You can also determine the field names of an externally defined structure from MATLAB using the following procedure:

  1. Use libfunctionsview to display the signatures for all functions in the library. libfunctionsview shows the names of the structures used by each function. For example, when you type:

    libfunctionsview shrlibsample

    MATLAB opens a new window displaying function signatures for the shrlibsample library. The line showing the addStructFields function reads:

    double addStructFields (c_struct)
  2. If the function you are using takes a structure argument, get the structure type from the libfunctionsview display, and invoke the libstruct function on that type. libstruct returns an object that is modeled on the structure as defined in the library:

    s = libstruct('c_struct');
  3. Get the names of the structure fields from the object returned by libstruct. Type:

    get(s)
    

    MATLAB displays:

        p1: 0 
        p2: 0 
        p3: 0
  4. Initialize the fields to the values you want to pass to the library function and make the call using calllib:

    s.p1 = 476;   s.p2 = -299;   s.p3 = 1000;
    calllib('shrlibsample','addStructFields',s);

Specifying Structure Field Names

Here are a few general guidelines that apply to structures passed to external library functions:

Passing a MATLAB® Structure

As with other data types, when an external function takes a structure argument (such as a C structure), you can pass a MATLAB structure to the function in its place. Structure field names must match field names defined in the library, but data types for numeric fields do not have to match. MATLAB converts each numeric field of the MATLAB structure to the correct data type.

Example of Passing a MATLAB® Structure.   The sample shared library, shrlibsample, defines the following C structure and function:

struct c_struct {
    double p1;
    short p2;
    long  p3;
};

double addStructFields(struct c_struct st)
{
    double t = st.p1 + st.p2 + st.p3;
    return t;
}

The following code passes a MATLAB structure, sm, with three double fields to addStructFields. MATLAB converts the fields to the double, short, and long data types defined in the C structure, c_struct. For example, type

sm.p1 = 476;   sm.p2 = -299;   sm.p3 = 1000;
calllib('shrlibsample', 'addStructFields', sm)

MATLAB displays:

ans =
        1177

Passing a libstruct Object

When you pass a structure to an external function, MATLAB makes sure that the structure being passed matches the library's definition for that structure type. It must contain all the necessary fields defined for that type and each field must be of the expected data type. For any fields that are missing in the structure being passed, MATLAB creates an empty field of that name and initializes its value to zero. For any fields that have a data type that doesn't match the structure definition, MATLAB converts the field to the expected type.

When working with small structures, it is efficient enough to have MATLAB do this work for you. You can pass the original MATLAB structure with calllib and let MATLAB handle the conversions automatically. However, when working with repeated calls that pass one or more large structures, it may be to your advantage to convert the structure manually before making any calls to external functions. In this way, you save processing time by converting the structure data only once at the start rather than at each function call. You can also save memory if the fields of the converted structure take up less space than the original MATLAB structure.

Preconverting a MATLAB® Struct with libstruct.   You can convert a MATLAB structure to a C-style structure derived from a specific type definition in the library in one step. Call the libstruct function, passing in the name of the structure type from the library, and the original structure from MATLAB. The syntax for libstruct is:

s = libstruct('structtype', mlstruct)

The value s returned by this function is called a libstruct object. Although it is truly a MATLAB object, it handles much like a MATLAB structure. The fields of this new "structure" are derived from the external structure type specified by structtype in the syntax above.

For example, to convert a MATLAB structure, sm, to a libstruct object, sc, that is derived from the c_struct structure type, use:

sm.p1 = 476;   sm.p2 = -299;   sm.p3 = 1000;
sc = libstruct('c_struct', sm);

All of fields in the original structure sm are of type double. The object sc, returned from the libstruct function, has fields that match the c_struct structure type. These fields are double, short, and long.

Creating an Empty libstruct Object.   You can also create an empty libstruct object by calling libstruct with only the structtype argument. The following statement constructs an object with all the required fields and with each field initialized to zero:

s = libstruct('structtype')

libstruct Requirements for Structures.   When converting a MATLAB structure to a libstruct object, the structure to be converted must adhere to the same guidelines that were documented for MATLAB structures passed directly to external functions. See Specifying Structure Field Names.

Using the Structure as an Object

The value returned by libstruct is not a true MATLAB structure. It is actually an instance of a class called lib.c_struct, as seen by examining the output of whos. Type:

whos

MATLAB displays (in part):

  Name      Size                   Bytes  Class

sc         1x1                           lib.c_struct
sm         1x1                      396  struct array

Determining the Size of a lib.c_struct Object.   You can use the lib.c_struct class method structsize to obtain the size of a lib.c_struct object:

sc.structsize

MATLAB displays:

ans = 
		16

Accessing lib.c_struct Fields.   The fields of this structure are implemented as properties of the lib.c_struct class. You can read and modify any of these fields using the MATLAB object-oriented functions, set and get:

sc = libstruct('c_struct');
set(sc, 'p1', 100, 'p2', 150, 'p3', 200);
get(sc)

MATLAB displays:

    p1: 100
    p2: 150
    p3: 200

You can also read and modify the fields by simply treating them like any other MATLAB structure fields:

sc.p1 = 23;
sc.p1

MATLAB displays:

ans =
   23

Example of Passing a libstruct Object

Repeat the addStructFields example, this time converting the structure to one of type c_struct before calling the function:

sm.p1 = 476;   sm.p2 = -299;   sm.p3 = 1000;
sc = libstruct('c_struct', sm);
get(sc)

MATLAB displays:

    p1: 476
    p2: -299
    p3: 1000

Now call the function, passing the structure sc:

calllib('shrlibsample', 'addStructFields', sc)

MATLAB displays:

ans =
    1177

Creating References

You can pass most arguments to an external function by value, even when the prototype for that function declares the argument to be a reference. The calllib function uses the header file to determine how to convert the function arguments.

There are times, however, when it is useful to pass MATLAB arguments that are the equivalent of C references:

In the cases above, you should use libpointer to construct a pointer object of a specified type (for structures use libstruct).

Constructing a Reference with the libpointer Function

To construct a reference, use the function libpointer with this syntax:

p = libpointer('type', 'value')

To give an example, create a pointer pv to an int16 value. In the first argument to libpointer, enter the type of pointer you are creating. The type is always the data type (int16, in this case) suffixed by the letters Ptr:

v = int16(485);
pv = libpointer('int16Ptr', v);

The value pv is an instance of a MATLAB lib.pointer class. The lib.pointer class has the properties Value and DataType. You can read and modify these properties with the MATLAB get and set functions:

get(pv)

MATLAB displays:

       Value: 485
    DataType: 'int16Ptr'

The lib.pointer class method setdatatype is described in Obtaining the Function's Return Values:

methods(pv)

MATLAB displays:

Methods for class lib.pointer:
   disp         plus         setdatatype  
   isNull       reshape

Creating a Reference to a Primitive Type

The following example illustrates how to construct and pass a pointer to type double, and how to interpret the output data. The function multDoubleRef takes one input that is a reference to a double and returns the same.

Here is the C function:

double *multDoubleRef(double *x)
{
     *x *= 5;
     return x;
}

Construct a reference, xp, to input data, x, and verify its contents:

x = 15;
xp = libpointer('doublePtr', x);
get(xp)

MATLAB displays:

       Value: 15
    DataType: 'doublePtr'

Now call the function and check the results:

calllib('shrlibsample', 'multDoubleRef', xp);
get(xp, 'Value')

MATLAB displays:

ans =
   75

Obtaining the Function's Return Values.   In the previous example, the result of the function called from MATLAB could be obtained by examining the modified input reference. But this function also returns data in its output arguments that may be useful.

The MATLAB prototype for this function (returned by libfunctions -full) indicates that MATLAB returns two outputs. The first is an object of class lib.pointer; the second is the Value property of the doublePtr input argument:

libfunctions shrlibsample -full
   [lib.pointer, doublePtr] multDoubleRef(doublePtr)

Run the example once more, but this time check the output values returned:

x = 15;
xp = libpointer('doublePtr', x);
[xobj, xval] = calllib('shrlibsample', 'multDoubleRef', xp)

MATLAB displays:

xobj =
   lib.pointer
xval =
    75

Like the input reference argument, the first output, xobj, is an object of class lib.pointer. You can examine this output, but first you need to initialize its data type and size as these factors are undefined when returned by the function. Use the setdatatype method defined by class lib.pointer to set the data type to doublePtr and the size to 1-by-1. Once initialized, you can examine outputs.

The first output is xobj:

setdatatype(xobj, 'doublePtr', 1, 1)
get(xobj)

MATLAB displays:

ans = 
       Value: 75
    DataType: 'doublePtr'

The second output, xval, is a double copied from the Value of input xp.

Creating a Reference by Offsetting from an Existing libpointer.   You can use the plus operator (+) to create a new pointer that is offset from an existing pointer by a scalar numeric value. Note that this operation applies only to pointer of numeric data types. For example, suppose you create a libpointer to the vector x:

x = 1:10;
xp = libpointer('doublePtr',x);
xp.Value

MATLAB displays:

ans =

     1     2     3     4     5     6     7     8     9    10

You can now use the plus operator to create a new libpointer that is offset from the xp:

xp2 = xp+4;
xp2.Value

MATLAB displays:

ans =

     5     6     7     8     9    10

Note that the new pointer (xp2 in this example) is valid only as long as the original pointer exists.

Creating a Structure Reference

Creating a reference argument to a structure is not much different than using a reference to a primitive type. The function shown here takes a reference to a structure of type c_struct as its only input. It returns an output argument that is the sum of all fields in the structure. It also modifies the fields of the input argument:

double addStructByRef(struct c_struct *st)
{
    double t = st->p1 + st->p2 + st->p3;
    st->p1 = 5.5;
    st->p2 = 1234;
    st->p3 = 12345678;
    return t;
 }

Passing the Structure Itself.   Although this function expects to receive a structure reference input, it is easier to pass the structure itself and let MATLAB do the conversion to a reference. This example passes a MATLAB structure, sm, to the function addStructByRef. MATLAB returns the correct value in the output, x, but does not modify the contents of the input, sm, since sm is not a reference:

sm.p1 = 476;   sm.p2 = -299;   sm.p3 = 1000;
x = calllib('shrlibsample', 'addStructByRef', sm)

MATLAB displays:

x =
        1177

Passing a Structure Reference.   The second part of this example passes the structure by reference. This time, the function receives a pointer to the structure and is then able to modify the structure fields.

sp = libpointer('c_struct', sm);
calllib('shrlibsample', 'addStructByRef', sp)

MATLAB displays:

ans =
        1177

Type:

get(sp, 'Value')

MATLAB displays:

ans = 
    p1: 5.5000
    p2: 1234
    p3: 12345678

Passing a Pointer to the First Element of an Array

In cases where a function defines an input argument that is a pointer to the first element of a data array, the calllib function automatically passes an argument that is a pointer of the correct type to the first element of data in the MATLAB vector or matrix. For example, the following C function sum requires an argument that is a pointer to the first element of an array of shorts (int16).

Suppose you define the following MATLAB variables :

Data = 1:100;
lp = libpointer('int16Ptr',Data);
shortData = int16(Data);

The signature of the C function sum is:

int sum(int size, short* data);

All of the following statements work correctly and give the same answer:

summed_data = calllib('libname','sum',100,Data);
summed_data = calllib('libname','sum',100,shortData);
summed_data = calllib('libname','sum',100,lp);

Note that the size and data arguments must match. That is, length of the data vector must be equal to the specified size. For example:

% sum last 50 elements
summed_data = calllib('libname','sum',50,Data(50:100)); 

Creating a Void Pointer to a String

Suppose you want to create a voidPtr that points to a string as an input argument. In C, characters are represented as unsigned eight-bit integers. Therefore, you must first cast the string to this MATLAB type before creating a variable of type voidPtr.

You can create a variable of the correct type and value using libpointer as follows:

str = 'string variable';
vp = libpointer('voidPtr',[uint8(str) 0]);

To obtain the character string from the pointer, type:

char(vp.Value)

MATLAB displays:

ans = 
string variable

Confirm the type of the pointer by accessing its DataType property, type:

vp.DataType

MATLAB displays:

ans = 
voidPtr

You can call a function that takes a voidPtr to a string as an input argument using the following syntax because MATLAB automatically converts an argument passed by value into an argument passed by reference when the external function prototype defines the argument as a reference:

func_name(uint8(str))

Note that while MATLAB converts the argument from a value to a reference, it must be of the correct type.

Memory Allocation for an External Library

In general, a valid memory address is passed each time you pass a MATLAB variable to a library function. You need to explicitly allocate memory only if the library provides a memory allocation function that you are required to use.

When to Use libpointer.   You should use a libpointer object in cases where the library is going to store the pointer and access the buffer over a period of time. In these cases, you need to ensure that MATLAB has control over the lifetime of the buffer and to prevent copies of the data from being made. The following pseudo code is an example of asynchronous data acquisition that shows how to use libpointer in this type of situation.

Suppose an external library has the following functions:

AcquireData(int points, short *buffer)
IsAquistionDone(void)

First, create a pointer to a buffer of 1024 points:

BufferSize = 1024;
pBuffer = libpointer('int16Ptr',1:BufferSize);

Then, begin acquiring data and wait in a loop until it is done:

calllib('lib_name','AcquireData,BufferSize,pbuffer);
while (~calllib('lib_name','IsAcquisitionDone')
	pause(0.1)
end

The following statement reads the data in the buffer:

result = pBuffer.Value;

When the library is done with the buffer, clear the MATLAB variable:

clear pBuffer

Reference Pointers

Arguments that have more than one level of referencing (e.g., uint16 **) are referred to here as reference pointers. In MATLAB, these argument types are named with the suffix PtrPtr (for example, uint16PtrPtr). See the output of libfunctionsview or methods -full for examples of this type.

When calling a function that takes a reference pointer argument, you can use a reference argument instead and MATLAB converts it to the reference pointer. For example, the external allocateStruct function expects a c_structPtrPtr argument:

libfunctions shrlibsample -full
   c_structPtrPtr allocateStruct(c_structPtrPtr)

Here is the C function:

void allocateStruct(struct c_struct **val)
{
    *val=(struct c_struct*) malloc(sizeof(struct c_struct));
    (*val)->p1 = 12.4;
    (*val)->p2 = 222;
    (*val)->p3 = 333333;
}

Although the prototype says that a c_structPtrPtr is required, you can use a c_structPtr and let MATLAB do the second level of conversion. Create a reference to an empty structure argument and pass it to allocateStruct:

sp = libpointer('c_structPtr');
calllib('shrlibsample', 'allocateStruct', sp)
get(sp)

MATLAB displays:

ans = 
       Value: [1x1 struct]
    DataType: 'c_structPtr'

Type:

get(sp, 'Value')

MATLAB displays:

ans = 
    p1: 12.4000
    p2: 222
    p3: 333333

Free memory using the command:

calllib('shrlibsample', 'deallocateStruct', sp)
  


 © 1984-2008- The MathWorks, Inc.    -   Site Help   -   Patents   -   Trademarks   -   Privacy Policy   -   Preventing Piracy   -   RSS