Main Content

coder.ceval

从生成的代码中调用 C/C++ 函数

说明

示例

out = coder.ceval(functionName,arg1,...,argN) 从生成的代码中调用在 functionName 中指定的 C/C++ 函数。可以在该函数调用中将一个或多个输入参量传递给调用的 C/C++ 函数。调用的 C/C++ 函数可以返回单个标量输出。例如,要使用输入 myChar 和输出 isNum 调用 C 标准函数 isalnum,请使用 isnum = coder.ceval("isalnum",myChar)

由于代码生成器在生成代码时不知道 C/C++ 函数返回的输出类型,您必须在 coder.ceval 调用之前指定 out 的类型(例如,通过为其赋予虚拟值)。用于保留非标量输出的变量可以通过使用 coder.ref (MATLAB Coder)coder.wref (MATLAB Coder) 按引用传递到被调用的 C/C++ 函数。

要调用 C/C++ 标准函数,您必须使用 coder.ceval"-headerfile"coder.cinclude (MATLAB Coder) 参量指定头文件。要调用自定义 C/C++ 函数,除了指定头文件外,还必须使用 coder.updateBuildInfo (MATLAB Coder) 指定外部源文件或库。

coder.ceval 函数只能在生成的代码中使用。在执行 MATLAB® 时调用 coder.ceval 会生成错误。要确定某个 MATLAB 函数是否正在 MATLAB 中执行,请使用 coder.target (MATLAB Coder)

示例

out = coder.ceval(options,functionName,arg1,...,argN) 使用在 options 参量中指定的选项从生成的代码中调用在 functionName 中指定的 C/C++ 函数。例如,使用 "-headerfile" 指定 C/C++ 头文件,使用 "-global" 指示调用的 C/C++ 函数使用全局变量。

示例

全部折叠

使用 coder.ceval 从生成的代码中调用 C 标准库函数 cosh()

创建一个 MATLAB 函数 callCosh,该函数接受类型为 double 的输入,以弧度表示角度,并使用 C 函数 cosh() 计算该角度的双曲余弦值。使用 coder.ceval 调用 cosh(),并使用 coder.cinclude 来包含在其中定义 cosh()math.h 头文件。将 math.h 用尖括号 <> 括起来,以将 math.h 识别为 C 标准头文件。

由于 coder.ceval 调用返回的输出类型在代码生成时未知,因此您必须将 coder.ceval 调用的输出转换为已知类型,方法是将输出赋给一个其类型已由之前的赋值定义的变量。如果没有这种事先赋值,代码生成将失败。

在 MATLAB 执行中调用 coder.ceval 会生成错误。使用 coder.target (MATLAB Coder) 确保在调用 coder.ceval 之前 callCosh 正在生成的代码中执行。

type callCosh.m
function out = callCosh(x)
arguments
    x (1,1) double
end
out = 0; % assign a dummy value to specify variable type
if coder.target("MATLAB")
    disp("This function not supported in MATLAB execution");
else
    coder.cinclude("<math.h>")
    out = coder.ceval("cosh",x);
end
end

在 MATLAB 中测试 callCoshcallCosh 不调用 coder.ceval

x = callCosh(1);
This function not supported in MATLAB execution

callCosh 生成一个 MEX 函数。

codegen callCosh
Code generation successful.

使用 π 弧度的角度测试生成的 MEX 函数 callCosh_mex。由于 callCosh 在生成的代码中执行,因此对 coder.ceval 的调用不会发生错误。

callCosh_mex(pi)
ans = 11.5920

callCosh 生成 C 代码并检查生成的代码。生成的 C 函数包含对 cosh() 的调用。

codegen -config:lib callCosh
Warning: Code generation is using a coder.EmbeddedCodeConfig object. Because
Embedded Coder is not installed, this might cause some Embedded Coder features
to fail.

Code generation successful (with warnings): To view the report, open('codegen/lib/callCosh/html/report.mldatx')
type(fullfile("codegen","lib","callCosh","callCosh.c"))
/*
 * File: callCosh.c
 *
 * MATLAB Coder version            : 24.1
 * C/C++ source code generated on  : 12-Feb-2024 20:57:41
 */

/* Include Files */
#include "callCosh.h"
#include <math.h>

/* Function Definitions */
/*
 * Arguments    : double x
 * Return Type  : double
 */
double callCosh(double x)
{
  /*  assign a dummy value to specify variable type */
  return cosh(x);
}

/*
 * File trailer for callCosh.c
 *
 * [EOF]
 */

使用 coder.ceval 从生成的代码中调用 C 函数 fopen()fclose()fscanf(),并使用这些函数读取包含逗号分隔值的文本文件的第一行。代码生成支持这些 C 函数的 MATLAB 等效函数 fopenfclosefscanf。此示例说明如何直接调用 C 文件 I/O 函数。

创建一个 MATLAB 函数 useCFileIO,该函数通过使用 coder.ceval 调用 C 文件 I/O 函数 fopen()fclose()fscanf() 来返回文本文件 data.csv 的第一行。使用 coder.cinclude 与尖括号以在生成的代码中包含 C 标准头文件 stdio.h,该文件定义了 C 文件 I/O 函数。使用 coder.opaque (MATLAB Coder) 将存储文件指针的变量初始化为类型为 FILE *、初始值为 NULL 的变量。

由于 coder.ceval 不支持数组输出,因此请使用 coder.wref 通过引用 C 函数 fscanf() 来传递输出变量 out。由于在代码生成时 out 的类型未知,因此请在 coder.ceval 调用之前使用虚拟值初始化此变量。如果没有此赋值,代码生成将失败。要将 MATLAB 字符向量传递给使用 coder.ceval 调用的 C/C++ 函数,必须用空字符 (0) 显式终止每个字符向量。有关详细信息,请参阅Generate C/C++ Strings from MATLAB Strings and Character Row Vectors (MATLAB Coder)

在 MATLAB 执行中调用 coder.ceval 会生成错误。使用 coder.target 确保在调用 coder.ceval 之前 useCFileIO 正在生成的代码中执行。

type useCFileIO.m
function out = useCFileIO %#codegen
fileName = 'data.csv';
if coder.target("MATLAB")
    fid = fopen(fileName);
    out = fscanf(fid, "%f,%f,%f",3);
    fclose(fid);
else
    coder.cinclude("<stdio.h>")
    fileName = [fileName 0];
    fileMode = ['r' 0];
    fileFormat = ['%lf,%lf,%lf' 0];
    fileHandle = coder.opaque("FILE*", "NULL");
    fileHandle = coder.ceval("fopen", fileName, fileMode);
    out = [0,0,0];
    coder.ceval("fscanf", fileHandle, fileFormat, ...
        coder.wref(out), coder.wref(out(2)), coder.wref(out(3)));
    coder.ceval("fclose", fileHandle);
end

useCFileIO 生成并测试 MEX 函数。

codegen useCFileIO
Code generation successful.
out = useCFileIO_mex
out = 1×3

    0.7071    0.6690    0.5985

useCFileIO 生成 C 代码并检查生成的代码。生成的 C 函数直接调用 fopen()fclose()fscanf()

codegen -config:lib -c useCFileIO
Warning: Code generation is using a coder.EmbeddedCodeConfig object. Because
Embedded Coder is not installed, this might cause some Embedded Coder features
to fail.

Code generation successful (with warnings): To view the report, open('codegen/lib/useCFileIO/html/report.mldatx')
type(fullfile("codegen","lib","useCFileIO","useCFileIO.c"))
/*
 * File: useCFileIO.c
 *
 * MATLAB Coder version            : 24.1
 * C/C++ source code generated on  : 12-Feb-2024 20:57:33
 */

/* Include Files */
#include "useCFileIO.h"
#include <stdio.h>

/* Function Definitions */
/*
 * Arguments    : double out[3]
 * Return Type  : void
 */
void useCFileIO(double out[3])
{
  static const char b_fileFormat[12] = "%lf,%lf,%lf";
  static const char b_fileName[9] = "data.csv";
  FILE *fileHandle;
  int i;
  char fileFormat[12];
  char fileName[9];
  for (i = 0; i < 9; i++) {
    fileName[i] = b_fileName[i];
  }
  char fileMode[2];
  fileMode[0] = 'r';
  fileMode[1] = '\x00';
  fileHandle = fopen(&fileName[0], &fileMode[0]);
  out[0] = 0.0;
  out[1] = 0.0;
  out[2] = 0.0;
  for (i = 0; i < 12; i++) {
    fileFormat[i] = b_fileFormat[i];
  }
  fscanf(fileHandle, &fileFormat[0], &out[0], &out[1], &out[2]);
  fclose(fileHandle);
}

/*
 * File trailer for useCFileIO.c
 *
 * [EOF]
 */

从 MATLAB 函数 addTwo 中调用自定义 C 函数 myAdd()

创建自定义 C 函数

创建 C 头文件 myAdd.h。在此头文件中,声明函数 myAdd(),此函数接受类型为 double 的两个输入参量,并返回类型为 double 的值。

type myAdd.h
double myAdd(double a, double b);

创建一个将两个输入参量相加的 C 函数 myAdd()。将该函数保存在 myAdd.c 中,并包含头文件 myAdd.h

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

double myAdd(double a, double b)
{
  return a + b;
}

创建调用自定义 C 函数的 MATLAB 函数

创建 MATLAB 函数 addTwo,该函数使用 coder.ceval 调用自定义 C 函数 myAdd()。创建一个模拟 myAdd() C 函数的局部 MATLAB 函数 myAddML。使用 coder.target (MATLAB Coder) 确保 addTwo 在 MATLAB 中执行时调用局部 MATLAB 函数 myAddML,在生成的代码中执行时调用 C 函数 myAdd()。使用 coder.updateBuildInfo (MATLAB Coder) 告知编译器在哪里可以找到包含 myAdd() 函数的 C 文件,并使用 coder.ceval"-headerfile" 选项指示代码生成器包含 myAdd.h 头文件。

type addTwo.m
function z = addTwo(x,y)  %#codegen
arguments
    x (1,1) double;
    y (1,1) double;
end
z = 0;
if coder.target("MATLAB")
    % Executing in MATLAB, call local MATLAB function
    z = myAddML(x,y);
else
    % Executing in generated code, call C function
    coder.updateBuildInfo("addSourceFiles","myAdd.c");
    z = coder.ceval("-headerfile","myAdd.h","myAdd",x,y);
end
end

function out = myAddML(a,b)
arguments
    a (1,1) double
    b (1,1) double
end
out = a + b;
end

生成并测试 MEX 函数

addTwo 生成 MEX 函数,并确保对于相同的输入,addTwo_mex 的输出与 addTwo 的输出匹配。

codegen addTwo
Code generation successful.
addTwo(4,5)
ans = 9
addTwo_mex(4,5)
ans = 9

生成和检查 C 代码

使用带 -config:lib 选项的 codegen 命令在命令行中从 addTwo 生成打包为独立 C 库的 C 代码。生成的 C 代码包括对 myAdd() C 函数的调用以及对 #include "myAdd.h" 指令的调用。

codegen -config:lib addTwo.m
Warning: Code generation is using a coder.EmbeddedCodeConfig object. Because
Embedded Coder is not installed, this might cause some Embedded Coder features
to fail.

Code generation successful (with warnings): To view the report, open('codegen/lib/addTwo/html/report.mldatx')
type(fullfile("codegen","lib","addTwo","addTwo.c"))
/*
 * File: addTwo.c
 *
 * MATLAB Coder version            : 24.1
 * C/C++ source code generated on  : 12-Feb-2024 20:58:09
 */

/* Include Files */
#include "addTwo.h"
#include "myAdd.h"

/* Function Definitions */
/*
 * Arguments    : double x
 *                double y
 * Return Type  : double
 */
double addTwo(double x, double y)
{
  /*  Executing in generated code, call C function */
  return myAdd(x, y);
}

/*
 * File trailer for addTwo.c
 *
 * [EOF]
 */

在 C++ 中,成员函数(亦称方法)是与特定类或对象相关联的函数。使用 coder.ceval 从生成的代码中调用自定义 C++ 类 MyClass 的公共方法。

创建简单的 C++ 类

出于此示例的目的,需要在文件 MyClass.hpp 中创建 C++ 类 MyClass。在此头文件中,定义函数 getValue(),该函数返回常量值。

type MyClass.hpp
class MyClass {
   public:
    double getValue() const {
        return 3.14;
    }
};

从生成的代码中调用成员函数

创建 MATLAB 函数 callGetValue,该函数调用 C++ 成员函数 getValue()。使用 coder.opaque (MATLAB Coder) 将变量 instanceOfMyClass 声明为 C++ 类 MyClass 的实例。使用 "HeaderFile" 参量指示 MyClass 是在头文件 MyClass.hpp 中定义的。

要使用 coder.ceval 从生成的代码中调用 getValue(),请使用 C++ 函数模板 std:mem_fn 来访问 getValue()。此函数模板在 C++ 标准头文件 <functional> 中定义。使用 coder.ref 将 instanceOfMyClass 传递给 getValue(),以强制代码生成器按引用而不是按值来传递此变量。

type callGetValue.m
function out = callGetValue
instanceOfMyClass = coder.opaque("MyClass", "MyClass{}", "HeaderFile", "MyClass.hpp");
out = 0;
out = coder.ceval("-headerfile", "<functional>", ...
    "std::mem_fn(&MyClass::getValue)", coder.ref(instanceOfMyClass));
end

生成并测试 MEX 函数

callGetValue 生成一个 MEX 函数,并确保该 MEX 函数产生预期的输出。要生成 C++ MEX 函数,请在 codegen 命令中指定 -lang:C++

codegen -lang:c++ callGetValue
Code generation successful.
callGetValue_mex
ans = 3.1400

生成和检查 C++ 代码

使用具有 -config:lib-lang:c++ 选项的 codegen 命令在命令行中从 callGetValue 生成打包为独立 C++ 库的 C++ 代码。生成的 C++ 代码会创建一个 MyClass 实例,并调用成员函数 getValue()

codegen -config:lib -lang:c++ callGetValue
Warning: Code generation is using a coder.EmbeddedCodeConfig object. Because
Embedded Coder is not installed, this might cause some Embedded Coder features
to fail.

Code generation successful (with warnings): To view the report, open('codegen/lib/callGetValue/html/report.mldatx')
type(fullfile("codegen","lib","callGetValue","callGetValue.cpp"))
//
// File: callGetValue.cpp
//
// MATLAB Coder version            : 24.1
// C/C++ source code generated on  : 12-Feb-2024 20:58:16
//

// Include Files
#include "callGetValue.h"
#include "MyClass.hpp"
#include <functional>

// Function Definitions
//
// Arguments    : void
// Return Type  : double
//
double callGetValue()
{
  MyClass instanceOfMyClass;
  instanceOfMyClass = MyClass{};
  return std::mem_fn(&MyClass::getValue)(&instanceOfMyClass);
}

//
// File trailer for callGetValue.cpp
//
// [EOF]
//

您可以使用 coder.ceval 来调用在自定义 C/C++ 库中定义的 C/C++ 函数。这些函数可以有自己的初始化和终止函数。

创建自定义 C 函数和库

出于此示例的目的,需要创建一个 MATLAB 函数 integrateSquare,用于计算区间 [min, max]x2 的定积分。为 integrateSquare 生成独立的 C 库。

type integrateSquare.m
function out = integrateSquare(min,max)
arguments
    min (1,1) double
    max (1,1) double
end
f = @(x) x.^2;
out = integral(f, min, max);
end
codegen -config:lib integrateSquare
Warning: Code generation is using a coder.EmbeddedCodeConfig object. Because
Embedded Coder is not installed, this might cause some Embedded Coder features
to fail.

Code generation successful (with warnings): To view the report, open('codegen/lib/integrateSquare/html/report.mldatx')

检查生成的 C 代码,该代码位于目录 codegen/lib/integrateSquare 中。integrateSquare 库和头文件以及包含 integrateSquare_initialize()integrateSquare_terminate() 函数定义的文件位于同一目录中。

type(fullfile("codegen","lib","integrateSquare","integrateSquare.c"))
/*
 * File: integrateSquare.c
 *
 * MATLAB Coder version            : 24.1
 * C/C++ source code generated on  : 12-Feb-2024 20:57:46
 */

/* Include Files */
#include "integrateSquare.h"
#include "integralCalc.h"
#include "integrateSquare_emxutil.h"
#include "integrateSquare_types.h"
#include "rt_nonfinite.h"
#include "rt_nonfinite.h"
#include <math.h>

/* Function Definitions */
/*
 * Arguments    : double b_min
 *                double b_max
 * Return Type  : double
 */
double integrateSquare(double b_min, double b_max)
{
  emxArray_real_T *interval;
  double A;
  double B;
  double delta;
  double out;
  double *interval_data;
  int MaxIntervalCount;
  int i;
  int nx;
  int y;
  signed char problemType;
  boolean_T guard1;
  boolean_T isinfA;
  boolean_T isinfB;
  boolean_T reversedir;
  MaxIntervalCount = 16384;
  emxInit_real_T(&interval);
  i = interval->size[0] * interval->size[1];
  interval->size[0] = 1;
  interval->size[1] = 2;
  emxEnsureCapacity_real_T(interval, i);
  interval_data = interval->data;
  if (b_max < b_min) {
    A = b_max;
    B = b_min;
    reversedir = true;
  } else {
    A = b_min;
    B = b_max;
    reversedir = false;
  }
  interval_data[0] = A;
  interval_data[1] = B;
  isinfA = rtIsInf(A);
  isinfB = rtIsInf(B);
  if (A == B) {
    problemType = 0;
  } else if (isinfA || isinfB) {
    if ((!isinfA) && isinfB) {
      interval_data[0] = 0.0;
      interval_data[1] = 1.0;
      problemType = 2;
    } else if (isinfA && (!isinfB)) {
      interval_data[0] = -1.0;
      interval_data[1] = 0.0;
      problemType = 3;
    } else if (isinfA && isinfB) {
      interval_data[0] = -1.0;
      interval_data[1] = 1.0;
      problemType = 4;
    } else {
      problemType = 0;
    }
  } else {
    interval_data[0] = -1.0;
    interval_data[1] = 1.0;
    problemType = 1;
  }
  i = interval->size[0] * interval->size[1];
  interval->size[0] = 1;
  interval->size[1] = 2;
  emxEnsureCapacity_real_T(interval, i);
  interval_data = interval->data;
  guard1 = false;
  if (problemType == 0) {
    guard1 = true;
  } else {
    double pathlen_tmp;
    int n_data;
    int nt;
    nx = 2;
    pathlen_tmp = interval_data[1] - interval_data[0];
    if (pathlen_tmp > 0.0) {
      n_data = (int)(ceil(pathlen_tmp * (10.0 / pathlen_tmp)) - 1.0);
      if (n_data <= 0) {
        y = 0;
      } else {
        y = n_data;
      }
      nt = y + 2;
      if (y >= 0) {
        nx = y;
      } else {
        nx = 0;
      }
      i = interval->size[0] * interval->size[1];
      interval->size[1] = nx + 2;
      emxEnsureCapacity_real_T(interval, i);
      interval_data = interval->data;
      for (i = 0; i < nx; i++) {
        interval_data[i + 2] = 0.0;
      }
      if (y + 2 > 2) {
        interval_data[y + 1] = interval_data[1];
        delta = (interval_data[1] - interval_data[0]) / (double)(n_data + 1);
        for (nx = n_data; nx >= 1; nx--) {
          interval_data[(y + nx) - n_data] =
              interval_data[0] + (double)nx * delta;
        }
      }
      nx = y + 2;
    } else {
      nt = 2;
    }
    n_data = 0;
    for (y = 2; y <= nx; y++) {
      delta = interval_data[y - 1];
      if (fabs(delta - interval_data[n_data]) > 0.0) {
        n_data++;
        interval_data[n_data] = delta;
      } else {
        nt--;
      }
    }
    if (nt < 2) {
      double b_interval;
      delta = interval_data[0];
      b_interval = interval_data[0];
      i = interval->size[0] * interval->size[1];
      interval->size[0] = 1;
      interval->size[1] = 2;
      emxEnsureCapacity_real_T(interval, i);
      interval_data = interval->data;
      interval_data[0] = delta;
      interval_data[1] = b_interval;
      nt = 2;
    } else {
      i = interval->size[0] * interval->size[1];
      interval->size[1] = nt;
      emxEnsureCapacity_real_T(interval, i);
    }
    nx = (nt - 1) << 1;
    if (nx > 16384) {
      MaxIntervalCount = nx;
    }
    if (!(pathlen_tmp > 0.0)) {
      guard1 = true;
    } else {
      out = scalarValuedIntegral(A, B, interval, nt, pathlen_tmp, problemType,
                                 MaxIntervalCount, &delta, &isinfA);
    }
  }
  if (guard1) {
    delta = (b_min + b_max) / 2.0;
    if ((!rtIsInf(b_min)) && (!rtIsNaN(b_min)) &&
        ((!rtIsInf(b_max)) && (!rtIsNaN(b_max))) &&
        (rtIsInf(delta) || rtIsNaN(delta))) {
      delta = b_min / 2.0 + b_max / 2.0;
    }
    out = (b_max - b_min) * (delta * delta);
  }
  emxFree_real_T(&interval);
  if (reversedir) {
    out = -out;
  }
  return out;
}

/*
 * File trailer for integrateSquare.c
 *
 * [EOF]
 */

创建 MATLAB 函数来调用自定义 C 函数

创建一个使用 coder.ceval 调用自定义 C 函数 integrateSquare() 的 MATLAB 函数 callIntegrateSquare。出于此示例的目的,需要在调用 integrateSquare() 之前调用 integrateSquare_initialize() 函数,然后再调用 integrateSquare_terminate() 函数。

使用 coder.updateBuildInfo (MATLAB Coder) 将包含 integrateSquare() 库和其他文件的目录添加到包含路径中。在对 coder.updateBuildInfo 函数的调用中,您可以使用 START_DIR 宏来引用当前工作文件夹。此宏只能在 MATLAB 代码中用于代码生成。由于 MATLAB 代码生成器生成具有特定于平台的扩展名的静态库文件,请使用 ispc 来确保您使用适合您平台的正确扩展名。

type callIntegrateSquare.m
function out = callIntegrateSquare(x,y) %#codegen
arguments
    x (1,1) double
    y (1,1) double
end
if coder.target("MATLAB")
    disp("Calling MATLAB function");
    out = integrateSquare(x,y);
else
    disp("Calling custom C function");
    out = 0;
    coder.updateBuildInfo("addIncludePaths", ...
        "$(START_DIR)/codegen/lib/integrateSquare");
    if ispc
        coder.updateBuildInfo("addLinkObjects","integrateSquare.lib", ...
            "$(START_DIR)/codegen/lib/integrateSquare","",true,true); 
    else
        coder.updateBuildInfo("addLinkObjects","integrateSquare.a", ...
            "$(START_DIR)/codegen/lib/integrateSquare","",true,true); 
    end  
    coder.ceval("-headerfile","integrateSquare_initialize.h", ...
        "integrateSquare_initialize");
    out = coder.ceval("-headerfile","integrateSquare.h","integrateSquare", ...
        x,y);
    coder.ceval("-headerfile","integrateSquare_terminate.h", ...
        "integrateSquare_terminate");
end
end

生成并测试 MEX 函数

callIntegrateSquare 生成一个 MEX 函数。确保 MATLAB 和 MEX 函数结果匹配。

codegen callIntegrateSquare
Code generation successful.
callIntegrateSquare(-2,2)
Calling MATLAB function
ans = 5.3333
callIntegrateSquare_mex(-2,2)
Calling custom C function
ans = 5.3333

生成和检查 C 代码

callIntegrateSquare 生成独立的 C 库,并检查生成的代码中对 integrateSquare_initialize()integrateSquare()integrateSquare_terminate() 的调用。

codegen -config:lib callIntegrateSquare
Warning: Code generation is using a coder.EmbeddedCodeConfig object. Because
Embedded Coder is not installed, this might cause some Embedded Coder features
to fail.

Code generation successful (with warnings): To view the report, open('codegen/lib/callIntegrateSquare/html/report.mldatx')
type(fullfile("codegen","lib","callIntegrateSquare","callIntegrateSquare.c"))
/*
 * File: callIntegrateSquare.c
 *
 * MATLAB Coder version            : 24.1
 * C/C++ source code generated on  : 12-Feb-2024 20:58:01
 */

/* Include Files */
#include "callIntegrateSquare.h"
#include "coder_platform.h"
#include "integrateSquare.h"
#include "integrateSquare_initialize.h"
#include "integrateSquare_terminate.h"
#include <stdio.h>

/* Function Definitions */
/*
 * Arguments    : double x
 *                double y
 * Return Type  : double
 */
double callIntegrateSquare(double x, double y)
{
  double out;
  printf("%s\n", "Calling custom C function");
  fflush(stdout);
  coderIsPC();
  integrateSquare_initialize();
  out = integrateSquare(x, y);
  integrateSquare_terminate();
  return out;
}

/*
 * File trailer for callIntegrateSquare.c
 *
 * [EOF]
 */

假设您有一个调用自定义 C 代码的 MATLAB 函数,该函数接受复数输入。您必须定义您的 C 代码输入参数,以便来自 MATLAB 函数的复数输入可以映射到您的 C 代码。

在生成代码中,复数定义为 struct,它有两个字段 reim,分别是复数的实部和虚部。此 struct 是在头文件 rtwtypes.h 中定义的,您可以在当前路径的 codegen\lib\functionName 文件夹中找到此头文件。struct 的定义如下:

typedef struct {
    real32_T re; /*Real Component*/
    real32_T im; /*Imaginary Component*/
} creal_T;

有关详细信息,请参阅 将 MATLAB 类型映射到生成的代码中的类型 (MATLAB Coder)

要集成的 C 代码必须包含 rtwtypes.h 头文件。C 代码示例 foo.c 如下所示:

#include "foo.h"
#include<stdio.h>
#include<stdlib.h>
#include "rtwtypes.h"

double foo(creal_T x) {
    double z = 0.0;
    z = x.re*x.re + x.im*x.im;
    return (z);
}

struct 命名为 creal_T。头文件 foo.h 也必须定义为:

#include "rtwtypes.h"
double foo(creal_T x);

MATLAB 代码通过使用具有复数输入的 coder.ceval 函数来执行 foo.c

function y = complexCeval  %#codegen
y = 0.0;
coder.updateBuildInfo("addSourceFiles","foo.c");
coder.cinclude("foo.h");
y = coder.ceval("foo", 10+20i);
end
coder.ceval 命令接受复数输入。代码生成器将复数映射到 struct creal_T 变量 x 及其字段 reim

通过运行以下命令,为函数 complexCeval 生成代码:

codegen -config:lib -report complexCeval

输入参数

全部折叠

要在生成的代码中执行的 C/C++ 函数的名称,指定为字符串标量或字符向量。functionName 在生成代码时必须为常量。

示例: x = coder.ceval("myFunction")

示例: coder.ceval("myFunction")

数据类型: char | string

调用的 C/C++ 函数的参量,指定为按照函数要求的顺序排列的、以逗号分隔的字符向量、数组、数组元素、结构体、结构体字段或对象属性列表。不支持字符串标量和字符串数组。

默认情况下,只要调用的 C/C++ 支持按值传递参量,coder.ceval 就会按值将参量传递给被调用的 C/C++ 函数。要强制 coder.ceval 按引用传递参量,请使用构造 coder.ref (MATLAB Coder)coder.rref (MATLAB Coder)coder.wref (MATLAB Coder)。在 C/C++ 不支持按值传递参量的情况下,例如当参量为数组时,coder.ceval 按引用传递参量。如果不使用 coder.refcoder.rrefcoder.wref,C/C++ 函数参量的副本可以出现在生成的代码中,以强制执行数组的 MATLAB 语义。

示例: x = coder.ceval("tolower",myChar)

示例: coder.ceval("myFunction",coder.ref(x))

数据类型: single | double | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64 | logical | char | struct
复数支持:

coder.ceval 计算的 C/C++ 函数调用的选项,指定为选项值或以逗号分隔的选项值列表。可以为 coder.ceval 函数指定多个选项,并且这些选项可以按任意顺序排列。所有选项(包括 headerfile)在代码生成时都必须为常量。下表显示对 coder.ceval 可用的选项。

选项描述
"-global"指定由 coder.ceval 调用的 C/C++ 函数使用一个或多个全局变量。-global 选项会禁止某些代码生成优化,因为这些优化可能会干扰调用的 C/C++ 函数中全局变量的使用。
"-gpudevicefcn"指定由 coder.ceval 调用的 C/C++ 函数位于 GPU 设备上。此选项允许您从内核中调用 CUDA® GPU __device__ 函数。此选项需要 GPU Coder™ 许可证。
"-headerfile","headerfile"

指定由 coder.ceval 调用的 C/C++ 函数在头文件 headerfile 中声明。代码生成器在生成的代码中为指定的头文件添加一条 #include 语句。您可以使用 coder.ceval"-headerfile" 参量,而不是单独调用 coder.cinclude (MATLAB Coder) 函数。使用 "-headerfile" 选项只能指定一个头文件。

要包含 C/C++ 标准头文件,请将头文件的名称用尖括号 <> 括起来。生成的 #include 语句的格式为 #include <headerfile>。标准头文件必须位于标准位置或包含路径中。

coder.ceval("-headerfile","<math.h>","atan",45)

要包含非标准头文件,请省略尖括号。生成的 #include 语句的格式为 #include "headerfile"。非标准头文件必须位于当前文件夹或包含路径中。

coder.ceval("-headerfile","myHeader","myFun")

要指定包含路径,请使用 addIncludePaths (MATLAB Coder)

"-layout:any"在生成的代码和调用的 C/C++ 函数之间传递输入和输出数据而无需更改数据布局,即使数组布局不匹配也是如此。这是默认行为。
"-layout:rowMajor""-row"在行优先布局中,在生成的代码和调用的 C/C++ 函数之间传递输入和输出数据。从使用列优先布局的 MATLAB 函数或 MATLAB Function 模块调用时,代码生成器会将输入转换为行优先布局,并将输出转换回列优先布局。
"-layout:columnMajor""-col"在列优先布局中,在生成的代码和调用的 C/C++ 函数之间传递输入和输出数据。从使用行优先布局的 MATLAB 函数或 MATLAB Function 模块调用时,代码生成器会将输入转换为列优先布局,并将输出转换回行优先布局。

示例: coder.ceval("-headerfile","myHeader.h","-layout:rowMajor","-global","myFunction",coder.rref(in),coder.wref(out));

限制

  • 对于您使用 coder.ceval 声明为外部函数的函数,不能使用 coder.extrinsic (MATLAB Coder)

  • 如果一个属性具有 get 方法、set 方法或验证器,或该属性是具有约束或修改属性值的特性的 System object™ 属性,则您无法通过引用外部函数来传递该属性。请参阅Passing By Reference Not Supported for Some Properties

  • 行优先代码生成不支持将可变大小矩阵作为入口函数参数。

提示

  • 要使用 coder.ceval 调用接受或返回 MATLAB 代码中不存在变量类型的 C/C++ 函数,如指针、用于文件 I/O 和 C/C++ 宏的 FILE 类型,请使用 coder.opaque 函数。

  • 使用 coder.ceval 调用的外部代码和生成的代码在同一个进程中运行,并共享内存。如果外部代码错误地写入包含生成的代码使用的数据结构体的内存,则可能导致意外行为或崩溃。例如,如果外部代码尝试在其终点后将数据写入数组,生成的代码可能会出现意外行为或崩溃。

  • MATLAB 在 Windows® 平台上使用 UTF-8 作为其系统编码。因此,从生成的 MEX 函数中进行的系统调用接受并返回 UTF-8 编码的字符串。相反,由 MATLAB Coder™ 生成的代码使用 Windows 区域设置指定的编码对文本数据进行编码。因此,如果您的 MATLAB 入口函数使用 coder.ceval (MATLAB Coder) 来调用接受不同系统编码的外部 C/C++ 函数,则生成的 MEX 函数可能会产生乱码文本。如果发生这种情况,您必须更新外部 C/C++ 函数。

扩展功能

C/C++ 代码生成
使用 MATLAB® Coder™ 生成 C 代码和 C++ 代码。

GPU 代码生成
使用 GPU Coder™ 为 NVIDIA® GPU 生成 CUDA® 代码。

版本历史记录

在 R2011a 中推出