Main Content

生成コードからのカスタム C/C++ コードの呼び出し

MATLAB® コード内から、カスタム コードまたはレガシ コードとも呼ばれる外部 C/C++ コードを直接呼び出すことができます。C/C++ 関数を呼び出すには、coder.ceval を使用します。コード ジェネレーターは C/C++ コードを MATLAB で生成された C/C++ コードに統合します。生成されたコードで使用する C/C++ で開発された外部ライブラリ、最適化されたコード、またはオブジェクト ファイルがあるときは、コードを統合します。外部コードが MATLAB で定義または認識されない変数の型を使用する場合、関数 coder.opaquecoder.ceval と共に使用します。生成コードと統合するカスタム C/C++ コードで使用するために特定の識別子名を予約するには、関数 coder.reservedName を使用します。

以下に示すのは、外部コード統合の基本的なワークフローの一部です。詳細については、coder.ceval のリファレンス ページを参照してください。

メモ

coder.ceval を使用することで、外部コードに制限なくアクセスできます。コード内にこれらの関数の誤用やエラーがあると、MATLAB が不安定になり、動作が停止する可能性があります。コードをデバッグし、コンパイルによるエラー メッセージを解析するには、コード生成レポートの [ビルド ログ] タブを表示します。

coder.ceval は、コード生成を目的とした MATLAB コードでのみ使用してください。コンパイルされていない MATLAB コードでは、coder.ceval はエラーを生成します。MATLAB 関数が MATLAB で実行されているかどうかを判断するには、coder.target を使用します。関数が MATLAB で実行されている場合、MATLAB バージョンの C/C++ 関数を呼び出します。

C コードの呼び出し

この例では、coder.ceval を使用して単純な C 関数を MATLAB® コードに統合する方法を説明します。MATLAB 関数 mathOps について考えます。

function [added, multed] = mathOps(in1, in2)
added = in1+in2;
multed = in1*in2; 
end

この例では、外部 C コードを使用して加算演算を実装するとします。ファイル adder.c で実装された C 関数 adder について考えます。

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

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

adder を MATLAB コードに統合するには、関数プロトタイプを含むヘッダー ファイルが必要です。ファイル adder.h を参照します。

double adder(double in1, double in2);

coder.ceval コマンドを使用して、mathOpsIntegrated.m 内で C 関数を呼び出します。coder.cinclude を使用してヘッダー ファイルを含めます。

function [added, multed] = mathOpsIntegrated(in1, in2)
%#codegen
% for code generation, preinitialize the output variable
% data type, size, and complexity 
added = 0;
% generate an include in the C code
coder.cinclude('adder.h');
% evaluate the C function
added = coder.ceval('adder', in1, in2); 
multed = in1*in2; 
end

コードを生成するには、codegen コマンドを使用します。ソース ファイル adder.c を入力として指定します。C コードをテストするには、MEX 関数を実行し、出力結果を検査します。

codegen mathOpsIntegrated -args {1, 2} adder.c

[test1, test2] = mathOpsIntegrated_mex(10, 20)
Code generation successful.


test1 =

    30


test2 =

   200

C 関数から複数の値を返す

C 言語では、関数が複数の出力を返すことを制限しています。その代わり、関数は単一のスカラー値のみを返します。MATLAB 関数の coder.refcoder.rref および coder.wref を使用することで、外部の C/C++ 関数から複数の出力を返すことができます。

たとえば、MATLAB 関数 foo を記述するとします。この関数は、x および y の 2 つの入力をとり、ab および c の 3 つの出力を返します。MATLAB では、この関数を次のように呼び出します。

[a,b,c] = foo(x,y)

foo を C 関数として書き換えると、3 つの別々の値 ab、および creturn ステートメントを通じて返すことはできません。代わりに、複数のポインター型引数をもつ C 関数を作成して、出力パラメーターを参照渡しします。以下に例を示します。

void foo(double x,double y,double *a,double *b,double *c)

次に、関数 coder.ceval を使用して、C 関数を MATLAB 関数から呼び出すことができます。

coder.ceval('foo',x,y,coder.ref(a),coder.ref(b),coder.ref(c));

外部 C 関数が参照渡しされるメモリに対して書き込みのみ、または読み取りのみを行う場合、関数 coder.ref ではなく関数 coder.wref または coder.rref を使用することができます。特定の状況では、これらの関数は生成されたコードのさらなる最適化を可能にします。coder.wref(arg) を使用して arg を参照渡しするときに、外部 C/C++ 関数は arg によって参照されるメモリを完全に初期化しなければなりません。

データの参照渡し

この例では、外部 C 関数との間でデータを参照渡しする方法を説明します。

参照渡しは C/C++ コード統合にとって重要な手法です。データを参照渡しするときに、プログラムはある関数から別の関数にデータをコピーする必要はありません。値渡しでは、C コードはスカラー変数を 1 つのみ返すことができます。参照渡しでは、C コードは配列を含む複数の変数を返すことができます。

MATLAB 関数 adderRef について考えます。この関数は、外部 C コードを使用して 2 つの配列を加算します。coder.rref コマンドと coder.wref コマンドは、コード ジェネレーターに対して、配列をコピーするのではなく配列へのポインターを渡すように指示します。

function out = adderRef(in1, in2)
%#codegen
out = zeros(size(in1)); 
% the input numel(in1) is converted to integer type 
% to match the cAdd function signature
coder.ceval('cAdd', coder.rref(in1), coder.rref(in2), coder.wref(out), int32(numel(in1)) );
end

C コード cAdd.c は線形インデックスを使用して配列の要素にアクセスします。

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

void cAdd(const double* in1, const double* in2, double* out, int numel)
{
    int i;
    for (i=0; i<numel; i++) {
        out[i] = in1[i] + in2[i];
    }
}

C コードを作成するには、関数シグネチャをもつヘッダー ファイル cAdd.h を指定しなければなりません。

void cAdd(const double* in1, const double* in2, double* out, int numel);

MEX 関数を生成して、その出力を MATLAB での加算演算の出力と比較することで、C コードをテストします。

A = rand(2,2)+1;
B = rand(2,2)+10;

codegen adderRef -args {A, B} cAdd.c cAdd.h -report

if (adderRef_mex(A,B) - (A+B) == 0)
    fprintf(['\n' 'adderRef was successful.']);
end
Code generation successful: To view the report, open('codegen/mex/adderRef/html/report.mldatx')


adderRef was successful.

カスタム データ型を使用する外部コードの統合

この例では、MATLAB® 内でネイティブに定義されていないデータ型を使用する C 関数を呼び出す方法を説明します。

たとえば、C コードが C 'FILE *' 型でファイルの入力または出力を実行する場合、MATLAB 内には対応する型が存在しません。MATLAB コード内のこのデータ型を操作するには、関数 coder.opaque を使用して初期化しなければなりません。構造体型の場合、coder.cstructname を使用できます。

たとえば、MATLAB 関数 addCTypes.m について考えます。この関数は、外部コードで定義された入力の型をもつ coder.ceval を使用します。関数 coder.opaque は MATLAB の型を初期化します。

function [out] = addCTypes(a,b)
%#codegen
% generate include statements for header files
coder.cinclude('MyStruct.h');
coder.cinclude('createStruct.h');
coder.cinclude('useStruct.h');
% initialize variables before use
in = coder.opaque('MyStruct');
out = 0;
% call C functions
in = coder.ceval('createStruct',a,b);
out = coder.ceval('useStruct',in); 
end


関数 createStruct は C 構造体型を出力します。

#include <stdio.h>
#include <stdlib.h>
#include "MyStruct.h"
#include "createStruct.h"

struct MyStruct createStruct(double a, double b) {
    struct MyStruct out;
    out.p1 = a;
    out.p2 = b;
    return out;
}

関数 useStruct は C の型で演算を実行します。

#include "MyStruct.h"
#include "useStruct.h"

double useStruct(struct MyStruct in) {
    return in.p1 + in.p2;
}

コードを生成するには、ソース (.c) ファイルを入力として指定します。

codegen addCTypes -args {1,2} -report createStruct.c useStruct.c
Code generation successful: To view the report, open('codegen/mex/addCTypes/html/report.mldatx')

ポインター、構造体、および配列を使用する外部コードの統合

この例は、C スタイルの配列を操作する外部コードを MATLAB® コードに統合する方法を示します。この外部コードは、配列データに対して総和計算を実行します。コードをカスタマイズして、入力データまたは計算を変更できます。

この例は、外部コード統合機能の複数の異なる要素を組み合わせる方法を示します。たとえば、次のようにします。

  • coder.cstructname を使用して、外部構造体型とインターフェイスをとる

  • coder.opaque を使用して、外部ポインター型とインターフェイスをとる

  • coder.ceval を使用して、外部コードを実行する

  • coder.ref を使用して、データを外部コードに参照渡しする

統合コードの確認

関数 extSum は、外部 C コードを使用して、32 ビットの整数配列に対して総和演算を計算します。配列のサイズはユーザー入力で制御されます。

function x = extSum(u)
%#codegen
% set bounds on input type to use static memory allocation
u = int32(u);
assert(0 < u && u < 101);
% initialize an array
temparray = int32(1):u;
% declare an external structure and use it
s = makeStruct(u);
x = callExtCode(s, temparray);


生成されるコードを簡略化するには、配列のサイズに範囲を設定します。範囲によって、生成されるコード内での動的なメモリ割り当ての使用を回避します。

関数 makeStruct は、MATLAB 構造体型を宣言し、coder.opaque を使用していずれかのフィールドをポインター型に初期化します。この定義に対応する C 構造体は、関数 coder.cstructnameHeaderFile パラメーターを使用して提供するヘッダー ファイル内に含まれています。C 構造体型では、整数の配列をシンプルに表現できます。

function s = makeStruct(u)
% create structure type based on external header definition
s.numel = u;
s.vals = coder.opaque('int32_T *','NULL');
coder.cstructname(s,'myArrayType','extern','HeaderFile','arrayCode.h');

外部構造体型が完全に初期化されたら、それを関数 callExtCode 内で外部コードに入力として渡します。この関数は配列を初期化し、配列に対する演算を呼び出して 1 つの出力を返し、初期化されたメモリを解放します。

function x = callExtCode(s, temparray)
% declare output type
x = int32(0);
% declare external source file
coder.updateBuildInfo('addSourceFiles','arrayCode.c');
% call c code
coder.ceval('arrayInit',coder.ref(s),coder.ref(temparray));
x = coder.ceval('arraySum',coder.ref(s));
coder.ceval('arrayDest',coder.ref(s));

関数は coder.updateBuildInfo を使用して .c ファイルをコード ジェネレーターに提供します。

MEX 関数の生成

MATLAB で実行およびテストできる MEX 関数を生成するには、次を入力します。

codegen extSum -args {10}
Code generation successful.

MEX 関数をテストします。次を入力します。

extSum_mex(10)
ans =

  int32

   55

ファイル arrayCode.carrayCode.h に含まれる外部 C コードは、カスタム型定義 int32_T を使用します。生成された MEX コードは、このカスタム型定義を生成および使用します。このカスタム データ型を使用するスタンドアロン (lib、dll、または exe) コードを生成する場合は、構成オブジェクトの DataTypeReplacement プロパティを変更できます。生成コードの型への MATLAB 型のマッピングを参照してください。

参考

| | | | | | | |

関連するトピック