メインコンテンツ

問題の解決: 変数は使用前に完全に定義する必要がある

問題

動的に型指定される言語である MATLAB® とは異なり、C と C++ は静的に型指定されます。つまり、コード ジェネレーターは、生成コードでの変数の定義と割り当てのために、MATLAB コード内のすべての変数の型を判別できる必要があります。コード ジェネレーターが MATLAB コード内の 1 つ以上の変数の型を判別できない場合、次の文を含むエラー メッセージがコード ジェネレーターから返されます。

コード生成では、すべての変数を使用前に完全に定義する必要があります。

表示されるエラー メッセージに cell 配列や cell 配列要素に関する言及がある場合は、問題の解決: cell 配列の要素は使用前に完全に定義する必要があるを参照してください。

考えられる解決策

この問題を解決するには、MATLAB コード内のすべての変数にすべての実行パスで値を代入します。これには、構造体フィールドやクラス プロパティなど、他のデータ構造体の中に含まれているすべての変数が含まれます。MATLAB コードと表示される具体的なエラー メッセージに応じて、次のいずれかの解決策を試してください。

すべての実行パスで変数に値を代入する

場合によっては、すべての変数がすべての実行パスで提供されていることをコード ジェネレーターで判別できないことがあります。たとえば、数値入力 x を受け取って x の絶対値を返す MATLAB 関数 undefinedVariableTest を作成します。

function y = undefinedVariableTest(x) %#codegen
arguments
    x (1,1) double
end
if x == 0
    y = 0;
elseif x < 0
    y = -x;
elseif x > 0
    y = x;
end
end
MATLAB の実行においては、undefinedVariableTest の呼び出しで x のすべての値について値が返されます。ただし、else ステートメントが見つからないため、考えられるすべての実行パスで y が定義されていることをコード ジェネレーターで判別できず、undefinedVariableTest のコード生成は失敗します。

このコードをコード生成に適したものにするには、else ステートメントを使用して、考えられるすべての実行パスで y が定義されていることをコード ジェネレーターに強制的に認識させます。

function y = undefinedVariableTest(x) %#codegen
arguments
    x (1,1) double
end
if x == 0
    y = 0;
elseif x < 0
    y = -x;
else
    y = x;
end
end

あるいは、if ステートメントの外側で y にダミー値を代入します。

function y = undefinedVariableTest(x) %#codegen
arguments
    x (1,1) double
end
y = 0;
if x == 0
    y = 0;
elseif x < 0
    y = -x;
elseif x > 0
    y = x;
end
end

すべての構造体フィールドとクラス プロパティに値を代入する

他のデータ型の中に含まれているすべての変数をすべての実行パスで定義する必要があります。構造体フィールドやクラス プロパティの数または形式は、構造体やクラスが使用された後は変更できません。さらに、特定のコーディング パターンでは、別のデータ型の中に含まれているすべての変数が定義されていることをコード ジェネレーターで認識できません。このような場合は、別のコーディング パターンを使用してコードを書き換えてみてください。

構造体フィールド。コード生成用の MATLAB コードでは、構造体を読み取るか、構造体にインデックスを付けるか、構造体を関数に渡した後は、その構造体にフィールドを追加することはできません。たとえば、構造体 y を返す MATLAB 関数 undefinedFieldTest を作成します。x が 10 より大きい場合、undefinedFieldTest は値を定義して構造体 s のフィールド field1 に代入します。それ以外の場合、undefinedFieldTest は値を定義して構造体 sfield1field2 に代入します。

function y = undefinedFieldTest(x) %#codegen
arguments
    x (1,1) double
end
if x > 10
    s.field1 = 11;
else
    s.field1 = 12;
    s.field2 = 12;
end
y = s;
end
MATLAB の実行においては、x が 10 以下の場合、構造体 s にフィールド field2 が動的に追加されます。ただし、コード ジェネレーターでは、x の実行時の値が不明な場合、構造体 s に含まれるすべてのフィールドの型をコード生成時に判別しなければなりません。フィールド field2 が一部の実行パスでは構造体 s の一部であるが、他の実行パスではそうでないことがコード ジェネレーターで検出されるため、コード生成は失敗します。

このコードをコード生成に適したものにするには、構造体に含まれるフィールドの数や名前が実行時に変わらないようにします。s のすべてのフィールドを x の実行時の値に依存せずに定義します。

function y = undefinedFieldTest(x) %#codegen
arguments
    x (1,1) double
end
s = struct("field1", [], "field2", []);
if x > 10
    s.field1 = 11;
else
    s.field1 = 12;
    s.field2 = 12;
end
y = s;
end
コード生成用の MATLAB コードでの構造体データ型の使用の詳細については、コード生成のための構造体の定義を参照してください。

クラス プロパティ。クラス プロパティにループで値を代入する特定のコーディング パターンでは、すべてのプロパティが定義されていることをコード ジェネレーターで認識できません。たとえば、正の整数の入力 n を受け取ってクラス MyClass のインスタンスを返す MATLAB 関数 undefinedPropTest を作成します。クラス MyClass には、prop1prop2 という 2 つのプロパティがあります。関数 undefinedPropTest は、返される myClass オブジェクトの prop1prop2for ループの内部で値を代入します。

function y = undefinedPropTest(n) %#codegen
arguments
    n (1,1) double {mustBePositive, mustBeInteger}
end
x = MyClass;
for i = 1:n
    x.prop1 = 1 + i;
    x.prop2 = x.prop1 + 3;
end
y = x;
end
MATLAB の実行においては、undefinedPropTest は、許容されるすべての n の値について MyClass のインスタンスを返します。ただし、n のすべての値について prop1prop2undefinedPropTest で値が代入されることをコード ジェネレーターで判別できないため、undefinedPropTest のコード生成は失敗します。

このコードをコード生成に適したものにするには、for ループの前に MyClass のすべてのプロパティにダミー値を代入します。

function y = undefinedPropTest(n) %#codegen
arguments
    n (1,1) double {mustBePositive, mustBeInteger}
end
x = MyClass;
x.prop1 = 0;
x.prop2 = 0;
for i = 1:n
    x.prop1 = 1 + i;
    x.prop2 = x.prop1 + 3;
end
y = x;
end
コード生成用の MATLAB コードでクラス プロパティを定義するときのその他の考慮事項については、コード生成のためのクラス プロパティの定義を参照してください。

すべての永続変数に初期値を代入する

MATLAB コード内のすべての persistent 変数をすべての実行パスで定義する必要があります。たとえば、呼び出された回数を persistent 変数 count に格納する MATLAB 関数 undefinedPersistentTest を作成します。count を初期化またはリセットするには、引数を 0 にして undefinedPersistentTest を呼び出す必要があります。

function y = undefinedPersistentTest(x)
persistent count;
if x == 0
    count = 0;
else
    count = count + 1;
end
y = count;
end

MATLAB では、永続変数が最初に検出されたときに、その変数が空の行列 ([]) になるように自動的に設定されます。そのため、count に値が与えられていても、undefinedPersistentTest の呼び出しでエラーは発生しません。ただし、コード ジェネレーターでは、初期化されていない永続変数のサイズや型はコード生成時に判別できません。したがって、x のすべての値について count が定義されていないことになり、undefinedPersistentTest のコード生成は失敗します。

このコードをコード生成に適したものにするには、この変数が未定義の場合の値を isempty 関数を使用して count に代入します。

function y = undefinedPersistentTest(x)
arguments
    x (1,1) double
end
persistent count;
if isempty(count)
    count = 0;
end
if x == 0
    count = 0;
else
    count = count + 1;
end
y = count;
end

代入なしで変数を定義する

場合によっては、生成コードでの代入による変数の定義には大きなオーバーヘッドが伴います。代入による変数の定義によって、生成コードに変数の余分なコピーができることもあります。変数の代入によるオーバーヘッドなしで変数の型、サイズ、実数/複素数を定義するには、coder.nullcopy を使用します。

coder.nullcopy を使用して変数を定義する場合、前述の認識されるコーディング パターンに従わなくてもコードを生成できます。たとえば、関数 nullcopyExample について考えます。この関数は coder.nullcopy を使用してクラス MyClass 用にメモリを事前に割り当てるため、このクラスのプロパティにダミー値を代入する必要はありません。

function y = nullcopyExample(n) %#codegen
arguments
    n (1,1) double {mustBePositive, mustBeInteger}
end
x = coder.nullcopy(MyClass);
for i = 1:n
    x.prop1 = 1 + i;
    x.prop2 = x.prop1 + 3;
end
y = x;
end

メモ

coder.nullcopy は注意して使用してください。クラス プロパティ、構造体フィールド、配列要素を含むすべての要素に値が代入されていることを確認する必要があります。初期化されていない変数にアクセスした場合、結果は予測できません。

参考

|

トピック