生成コードからのカスタム C/C++ コードの呼び出し
MATLAB® コード内から、カスタム コードまたはレガシ コードとも呼ばれる外部 C/C++ コードを直接呼び出すことができます。C/C++ 関数を呼び出すには、coder.ceval
を使用します。コード ジェネレーターは C/C++ コードを MATLAB で生成された C/C++ コードに統合します。生成されたコードで使用する C/C++ で開発された外部ライブラリ、最適化されたコード、またはオブジェクト ファイルがあるときは、コードを統合します。外部コードが MATLAB で定義または認識されない変数の型を使用する場合、関数 coder.opaque
を coder.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.ref
、coder.rref
および coder.wref
を使用することで、外部の C/C++ 関数から複数の出力を返すことができます。
たとえば、MATLAB 関数 foo
を記述するとします。この関数は、x
および y
の 2 つの入力をとり、a
、b
および c
の 3 つの出力を返します。MATLAB では、この関数を次のように呼び出します。
[a,b,c] = foo(x,y)
foo
を C 関数として書き換えると、3 つの別々の値 a
、b
、および c
を return
ステートメントを通じて返すことはできません。代わりに、複数のポインター型引数をもつ 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.cstructname
の HeaderFile
パラメーターを使用して提供するヘッダー ファイル内に含まれています。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.c
と arrayCode.h
に含まれる外部 C コードは、カスタム型定義 int32_T
を使用します。生成された MEX コードは、このカスタム型定義を生成および使用します。このカスタム データ型を使用するスタンドアロン (lib、dll、または exe) コードを生成する場合は、構成オブジェクトの DataTypeReplacement
プロパティを変更できます。生成コードの型への MATLAB 型のマッピングを参照してください。
参考
codegen
| coder.wref
| coder.ceval
| coder.rref
| coder.ref
| coder.cinclude
| coder.cstructname
| coder.opaque
| coder.reservedName