主要内容

Pass by Reference to and from External C Functions

This example shows how integrate external C code into your MATLAB code for code generation. In this example, the MATLAB function passes data by reference to and from the external C function. When you pass data by reference, the function passes a pointer to the data. So, if you change the data in one function workspace, the changes also appear in the other function workspace. In addition, you can use pass-by-reference to write C code that returns multiple variables, including arrays.

Examine C Function Definition

Examine the C function cAddMult. This function takes as inputs an integer value, numels, and four pointers to arrays of doubles. It uses linear indexing to access each element of the array input1. It creates the output arrays addOut and multOut by adding or multiplying each element of input1 with the corresponding element of input2.

type cAddMult.c
#include <stdio.h>
#include <stdlib.h>
#include "cAddMult.h"  

void cAddMult(const double* input1, const double* input2, 
              double* addOut, double* multOut, int numels)
{
    int i;
    for (i=0; i<numels; i++) {
        addOut[i] = input1[i]+input2[i];
        multOut[i] = input1[i]*input2[i];
        
    }
}

Examine and Test MATLAB Function

Examine the MATLAB function addAndMult, which uses coder.ceval to call the C function cAddMult in the generated code. In MATLAB, calls to coder.ceval produce an error. This function uses coder.target to make sure that it only calls coder.ceval in the generated code. The MATLAB function passes the input and output arrays to and from the C function by reference by using coder.ref. So, the C function can return more than one scalar value. The MATLAB function uses an arguments block to define the input arguments x and y as unbounded arrays of doubles. Because the code generator does not know the type of the output the C function returns at code generation time, the function preallocates the output arrays.

type addAndMult.m
function [addOut,multOut] = addAndMult(x,y) %#codegen
arguments
    x (:,:) double
    y (:,:) double
end
addOut = zeros(size(x));
multOut = zeros(size(x));
if coder.target("MATLAB")
    for i = 1:numel(x)
        addOut(i) = x(i)+y(i);
        multOut(i) = x(i)*y(i);
    end
else
    coder.ceval('cAddMult',coder.ref(x),coder.ref(y), ...
        coder.ref(addOut),coder.ref(multOut),int32(numel(x)));
end
end

Generate sample arrays and use them to test the MATLAB function.

A = magic(3);
B = magic(5);

[x,y] = addAndMult(A,B)
x = 3×3

    25    11    11
    26    16    13
     8    33    14

y = 3×3

   136    10    30
    69    55    42
    16   216    24

Generate and Run MEX Function

Generate a MEX function for the addAndMult function by using the codegen command. Then, run the generated MEX function to check that the generated code has the same behavior as the original MATLAB code.

By default, the codegen command generates a MEX function in C in the working folder. Instruct the code generator to include the C function declaration and definition in the generated code by specifying the custom source files cAddMult.c and cAddMult.h. Because the addAndMult function uses an arguments block to declare input arguments, you do not have to pass input types to the codegen command.

codegen addAndMult cAddMult.c cAddMult.h
Code generation successful.

Test the MEX function with the same inputs that you passed to the original MATLAB function. The MEX function produces the same output.

[x_MEX,y_MEX] = addAndMult_mex(A,B)
x_MEX = 3×3

    25    11    11
    26    16    13
     8    33    14

y_MEX = 3×3

   136    10    30
    69    55    42
    16   216    24

Generate and Inspect C Code

Generate a C static library by using the codegen command with the -config:lib option. Specify the custom source files cAddMult.c and cAddMult.h.

codegen -config:lib addAndMult cAddMult.c cAddMult.h
Code generation successful.

Examine the definition of the C function addAndMult in the generated code. Most of the code for this function handles variable-size inputs. Examine the call to cAddMult. The ampersand (&) preceding each array argument indicates that addAndMult function passes these arguments to cAddMult by reference.

file = fullfile("codegen","lib","addAndMult","addAndMult.c");
coder.example.extractLines(file,"void addAndMult","/*",1,0)
void addAndMult(emxArray_real_T *x, emxArray_real_T *y, emxArray_real_T *addOut,
                emxArray_real_T *multOut)
{
  double *addOut_data;
  double *multOut_data;
  double *x_data;
  double *y_data;
  int i;
  int i1;
  int loop_ub;
  y_data = y->data;
  x_data = x->data;
  i = addOut->size[0] * addOut->size[1];
  addOut->size[0] = x->size[0];
  addOut->size[1] = x->size[1];
  emxEnsureCapacity_real_T(addOut, i);
  addOut_data = addOut->data;
  loop_ub = x->size[0] * x->size[1];
  for (i1 = 0; i1 < loop_ub; i1++) {
    addOut_data[i1] = 0.0;
  }
  i = multOut->size[0] * multOut->size[1];
  multOut->size[0] = x->size[0];
  multOut->size[1] = x->size[1];
  emxEnsureCapacity_real_T(multOut, i);
  multOut_data = multOut->data;
  for (i1 = 0; i1 < loop_ub; i1++) {
    multOut_data[i1] = 0.0;
  }
  cAddMult(&x_data[0], &y_data[0], &addOut_data[0], &multOut_data[0],
           x->size[0] * x->size[1]);
}

See Also

| | |

Topics