Main Content

本页的翻译已过时。点击此处可查看最新英文版本。

coder.ceval

调用外部 C/C++ 函数

说明

示例

coder.ceval(cfun_name) 执行 cfun_name 指定的外部 C/C++ 函数。在外部 C/C++ 源文件或库中定义 cfun_name。将外部源代码、库和头文件提供给代码生成器。

示例

coder.ceval(cfun_name,cfun_arguments) 使用参数 cfun_arguments 执行 cfun_namecfun_arguments 是按照 cfun_name 要求的顺序排列的逗号分隔的输入参数列表。

默认情况下,只要 C/C++ 支持按值传递参数,coder.ceval 就会按值向 C/C++ 函数传递参数。要使 coder.ceval 按引用传递参数,请使用 coder.refcoder.rrefcoder.wref 构造。如果 C/C++ 不支持按值传递参数,例如说参数是一个数组,则 coder.ceval 将按引用传递参数。如果您不使用 coder.refcoder.rrefcoder.wref,则生成的代码中可能会出现参数的副本,以强制执行用于数组的 MATLAB® 语义。

示例

coder.ceval('-global',cfun_name) 执行 cfun_name,并指示 cfun_name 使用一个或多个 MATLAB 全局变量。然后,代码生成器可以产生与此全局变量用法一致的代码。

coder.ceval('-global',cfun_name,cfun_arguments) 使用参数 cfun_arguments 执行 cfun_name,并指示 cfun_name 使用一个或多个 MATLAB 全局变量。

coder.ceval('-gpudevicefcn',devicefun_name,devicefun_arguments) 允许您从核内调用 CUDA® GPU __device__ 函数。'-gpudevicefcn'coder.ceval 指示目标函数在 GPU 设备上。devicefun_name__device__ 函数的名称,devicefun_arguments 是按 devicefun_name 要求的顺序以逗号分隔的输入参数列表。此选项需要 GPU Coder™ 产品。

示例

coder.ceval('-layout:rowMajor',cfun_name,cfun_arguments) 带参数 cfun_arguments 执行 cfun_name,并传递以行优先布局存储的数据。当从使用列优先布局的函数调用时,代码生成器将输入转换为行优先布局,并将输出转换回列优先布局。要获得更短的语法,请使用 coder.ceval('-row',...)

coder.ceval('-layout:columnMajor',cfun_name,cfun_arguments) 带参数 cfun_arguments 执行 cfun_name,并传递以列优先布局存储的数据。当从使用行优先布局的函数调用时,代码生成器将输入转换为列优先布局,并将输出转换回行优先布局。要获得更短的语法,请使用 coder.ceval('-col',...)

coder.ceval('-layout:any',cfun_name,cfun_arguments) 带参数 cfun_arguments 执行 cfun_name,并使用当前数组布局传递数据,即使数组布局不匹配也是如此。代码生成器不转换输入或输出数据的数组布局。

示例

cfun_return = coder.ceval(___) 执行 cfun_name 并返回单个标量值 cfun_return,它对应于 C/C++ 函数在 return 语句中返回的值。为了与 C/C++ 保持一致,coder.ceval 只能返回标量值。它不能返回数组。可以将此选项与前面语法中的任何输入参数组合一起使用。

示例

全部折叠

从要从其生成 C 代码的 MATLAB 函数调用 C 函数 foo(u)

为函数 foo 创建 C 头文件 foo.h,该函数接受两个 double 类型的输入参数,并返回 double 类型的值。

double foo(double in1, double in2);

编写 C 函数 foo.c

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

double foo(double in1, double in2)
{
  return in1 + in2;
}

编写使用 coder.ceval 调用 foo 的函数 callfoo。将源代码和头文件提供给函数中的代码生成器。

function y = callfoo  %#codegen
y = 0.0;
if coder.target('MATLAB')
    % Executing in MATLAB, call MATLAB equivalent of
    % C function foo
    y = 10 + 20;
else
    % Executing in generated code, call C function foo
    coder.updateBuildInfo('addSourceFiles','foo.c');
    coder.cinclude('foo.h');
    y = coder.ceval('foo', 10, 20);
end
end

为函数 callfoo 生成 C 库代码。codegen 函数在 \codegen\lib\callfoo 子文件夹中生成 C 代码。

codegen -config:lib callfoo -report

从 MATLAB 代码中调用 C 库函数:

编写 MATLAB 函数 myabsval

function y = myabsval(u)   
%#codegen
y = abs(u);

通过使用 -args 选项指定输入参数的大小、类型和复/实性,为 myabsval 生成 C 静态库。

codegen -config:lib myabsval -args {0.0}
codegen 函数在文件夹 \codegen\lib\myabsval 中创建库文件 myabsval.lib 和头文件 myabsval.h。(库文件扩展名可以根据您的平台而有所不同。)它在同一个文件夹中生成函数 myabsval_initializemyabsval_terminate

编写一个 MATLAB 函数,以使用 coder.ceval 调用生成的 C 库函数。

function y = callmyabsval(y)  
%#codegen
% Check the target. Do not use coder.ceval if callmyabsval is
% executing in MATLAB
if coder.target('MATLAB')
  % Executing in MATLAB, call function myabsval
  y = myabsval(y);
else
  % add the required include statements to generated function code
  coder.updateBuildInfo('addIncludePaths','$(START_DIR)\codegen\lib\myabsval');
  coder.cinclude('myabsval_initialize.h');
  coder.cinclude('myabsval.h');
  coder.cinclude('myabsval_terminate.h');

  % Executing in the generated code. 
  % Call the initialize function before calling the 
  % C function for the first time
  coder.ceval('myabsval_initialize');

  % Call the generated C library function myabsval
  y = coder.ceval('myabsval',y);
  
  % Call the terminate function after
  % calling the C function for the last time
  coder.ceval('myabsval_terminate');
end

生成 MEX 函数 callmyabsval_mex。在命令行中提供生成的库文件。

codegen -config:mex callmyabsval codegen\lib\myabsval\myabsval.lib -args {-2.75}

您可以使用 coder.updateBuildInfo 在函数中指定该库,而不是在命令行中提供库。使用此选项可预配置编译。将以下行添加到 else 模块中:

coder.updateBuildInfo('addLinkObjects','myabsval.lib','$(START_DIR)\codegen\lib\myabsval',100,true,true);

运行调用库函数 myabsval 的 MEX 函数 callmyabsval_mex

callmyabsval_mex(-2.75)
ans =

    2.7500

调用 MATLAB 函数 callmyabsval

callmyabsval(-2.75)
ans =

    2.7500
callmyabsval 函数在 MATLAB 和代码生成中的执行均展示出了预期的行为。

调用修改全局变量的 C 函数时,请使用 '-global' 标志。

编写调用 C 函数 addGlobal 的 MATLAB 函数 useGlobal。使用 '-global' 标志向代码生成器指示 C 函数使用全局变量。

function y = useGlobal()
global g;
t = g;
% compare execution with/without '-global' flag
coder.ceval('-global','addGlobal'); 
y = t;
end

为函数 addGlobal 创建 C 头文件 addGlobal.h

void addGlobal(void);

在文件 addGlobal.c 中编写 C 函数 addGlobal。此函数包含代码生成器在您为函数 useGlobal 生成代码时创建的头文件 useGlobal_data.h。此头文件包含 g 的全局变量声明。

#include "addGlobal.h"
#include "useGlobal_data.h"
void addGlobal(void) {
    g++;
}

useGlobal 生成 MEX 函数。要定义代码生成器的输入,请在工作区中声明全局变量。

global g;
g = 1;
codegen useGlobal -report addGlobal.h addGlobal.c
y = useGlobal_mex();

使用 '-global' 标志时,MEX 函数产生结果 y = 1'-global' 标志向代码生成器指示 C 函数可能修改全局变量。对于 useGlobal,代码生成器产生以下代码:

real_T useGlobal(const emlrtStack *sp)
{
  real_T y;
  (void)sp;
  y = g;
  addGlobal();
  return y;
}

如果没有 '-global' 标志,MEX 函数将产生 y = 2。因为没有关于 C 函数修改 g 的指示,代码生成器假定 yg 是相同的。将生成以下 C 代码:

real_T useGlobal(const emlrtStack *sp)
{
  (void)sp;
  addGlobal();
  return g;
}

假设您有设计为使用行优先布局的 C 函数 testRM。您要将此函数集成到对数组执行运算的 MATLAB bar 函数中。函数 bar 设计为使用列优先布局,采用 coder.columnMajor 指令。

function out = bar(in)
%#codegen
coder.columnMajor;
coder.ceval('-layout:rowMajor','testRM', ...
    coder.rref(in),coder.wref(out));
end

在生成的代码中,代码生成器会先在变量 in 上插入从列优先布局到行优先布局的布局转换,然后再将其传递给 testRM。在输出变量 out 上,代码生成器会插入一个转换回列优先布局的布局转换。

通常,如果您没有为 coder.ceval 指定 layout 选项,则外部函数参数假定使用列优先布局。

假设您有一个调用自定义 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*/
} creal32_T;

有关详细信息,请参阅 Mapping MATLAB Types to Types in Generated Code

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

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

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

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

#include "rtwtypes.h"
double foo(creal32_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 creal32_T 变量 x 及其字段 reim

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

codegen -config:lib -report complexCeval

输入参数

全部折叠

要调用的外部 C/C++ 函数的名称。

示例: coder.ceval('foo')

数据类型: char | string

按照 cfun_name 要求的顺序排列的逗号分隔的输入参数列表。

示例: coder.ceval('foo', 10, 20);

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

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

限制

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

  • 当 LCC 编译器创建库时,它会向库函数名称添加一个前导下划线。如果库的编译器是 LCC,而您的代码生成编译器不是 LCC,则您必须向函数名称添加前导下划线,例如 coder.ceval('_mylibfun')。如果库的编译器不是 LCC,而 MATLAB 代码从该库中调用函数,则您不能使用 LCC 从该代码中生成代码。这些库函数名称没有 LCC 编译器所要求的前导下划线。

  • 如果某属性具有 get 方法、set 方法或验证程序,或者是具有某些特性的 System object™ 属性,则您不能通过引用外部函数传递该属性。请参阅Passing By Reference Not Supported for Some Properties

提示

  • 对于代码生成,您必须在调用 coder.ceval 之前指定返回值和输出参数的类型、大小和复/实性数据类型。

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

  • coder.ceval 只能在 MATLAB 中用于代码生成。在未编译的 MATLAB 代码中,coder.ceval 将生成错误。要确定 MATLAB 函数是否在 MATLAB 中执行,请使用 coder.target。如果函数在 MATLAB 中执行,则调用 C/C++ 函数的 MATLAB 版本。

在 R2011a 中推出