Main Content

実行時エラーを検出および報告するスタンドアロン C/C++ コードの生成

開発中は、C/C++ コードを生成する前に、アルゴリズムの MEX バージョンを実行して生成コードをテストすることをお勧めします。ただし、ターゲット ハードウェアでしか発生しないエラーもあります。それらのエラーを検出するには、範囲外の配列インデックスなどの実行時エラーを検出して報告するスタンドアロンのライブラリと実行可能ファイルを生成します。

既定では、実行時エラーの検出は、スタンドアロンのライブラリと実行可能ファイルに対しては無効になっています。実行時エラーの検出とレポートをスタンドアロンのライブラリと実行可能ファイルに対して有効にするには、次を行います。

  • コマンド ラインで、コード構成プロパティ RuntimeChecks を使用します。

    cfg = coder.config('lib'); % or 'dll' or 'exe'
    cfg.RuntimeChecks = true;
    codegen -config cfg myfunction
  • MATLAB® Coder™ アプリで、[プロジェクトの設定] ダイアログ ボックスの [デバッグ] ペインにある [実行時エラー チェックの生成] チェック ボックスをオンにします。

実行時エラーの検出は生成されたコードのパフォーマンスに影響する場合があります。パフォーマンスがアプリケーションの考慮事項になっている場合、量産コードの生成時は実行時エラーの検出を有効にしないでください。

生成された C コードと生成された C++ コード

ターゲット言語が C の場合、生成されたコードは fprintf を使用してエラー メッセージを stderr に書き込みます。その後、コードは abort を使用してアプリケーションを終了します。fprintf および abort が使用できない場合、指定しなければなりません。関数 abort はプログラムを突然終了します。信号がシステムでサポートされている場合、中止信号 (SIGABRT) を検出してプログラムの終了を制御できます。

ターゲット言語が C++ の場合、生成されたコードは実行時エラーに対して std::runtime_error 例外をスローします。生成された C++ エントリポイント関数を呼び出すときに、外部 C++ コードで try-catch ブロックを使用することにより、それらの例外をキャッチして処理できます。

ただし、生成された C++ コードは、並列領域 (parfor ループまたは自動並列化 for ループ) の内部にある実行時エラー チェックについては例外をスローしません。このような場合、生成されたコードは fprintf を使用してエラー メッセージを stderr に書き込み、abort を使用してアプリケーションを終了します。自動並列化の詳細については、生成コードでの for ループの自動並列化を参照してください。

例: 実行時チェックを含む生成された C コードと C++ コードの比較

この例では、入力引数の平方根を計算する MATLAB® 関数の生成コードで C コードと C++ コードの実行時の動作を比較します。生成されたコードは非負の実数値のみを受け入れ、負の入力に対しては実行時エラーを生成します。

  • 生成された C コードは、fprintf を使用してエラー メッセージを stderr に書き込みます。その後、コードは abort を使用してアプリケーションを終了します。

  • 生成された C++ コードは、この実行時エラーに対して std::runtime_error 例外をスローします。生成された関数の呼び出し用に記述する C++ の main 関数で try-catch ブロックを使用することにより、この例外をキャッチして処理できます。

MATLAB 関数の定義

MATLAB 関数 errorCheckExample を独立したファイルで定義します。この関数は入力引数の平方根を計算します。

type errorCheckExample
function y = errorCheckExample(x)
y = sqrt(x);
end

C のライブラリと実行可能ファイルの生成

double のスカラー入力を受け入れる errorCheckExample の C ダイナミック リンク ライブラリを生成します。コード構成オブジェクトを使用して RuntimeChecks パラメーターを true に設定します。さらに、-d オプションを使用して、コード生成フォルダーに codegen_c_dll という名前を付けます。

cfg = coder.config('dll');
cfg.RuntimeChecks = true;
codegen -config cfg errorCheckExample -args 1 -d codegan_c_dll -report
Code generation successful: To view the report, open('codegan_c_dll/html/report.mldatx')

コード生成レポートを開き、ファイル errorCheckExample.c を検査します。MATLAB 関数に対して生成された C 関数のシグネチャは double errorCheckExample(double x) です。平方根を計算するために、errorCheckExample は実数の平方根のみを計算するライブラリ関数 sqrt を呼び出します。そのため、errorCheckExample は正の入力のみを受け入れます。負の入力に対しては、errorCheckExample は生成されたユーティリティ関数 rtErrorWithMessageID を呼び出します。この関数は、fprintf を使用してエラー メッセージを stderr に書き込み、abort を使用してアプリケーションを終了します。

static void rtErrorWithMessageID(const int b, const char *c,
                                 const char *aFcnName, int aLineNum)
{
  fprintf(stderr,
          "Domain error. To compute complex results from real x, use "
          "\'%.*s(complex(x))\'.",
          b, c);
  fprintf(stderr, "\n");
  fprintf(stderr, "Error in %s (line %d)", aFcnName, aLineNum);
  fprintf(stderr, "\n");
  fflush(stderr);
  abort();
}

ライブラリ コードを生成する際に、コード ジェネレーターはメイン ファイルの例 main.h および main.c もビルド フォルダーの examples サブフォルダーに生成しています。C サポート ファイル main_runtime_check.h および main_runtime_check.c は、これらのサンプル ファイルを変更したものです。変更された main 関数は、実行時エラーを生成する errorCheckExample(-4) を呼び出します。

次のコマンドを実行して、変更されたメイン ファイルを使用する C 実行可能ファイルを生成します。コード生成フォルダーに codegen_c_exe という名前を付けます。codegen コマンドで -o オプションを使用して、実行可能ファイルに errorCheckExample_c という名前を付けます。

cfg = coder.config('exe');
cfg.RuntimeChecks = true;
cfg.CustomSource = 'main_runtime_check.c';
cfg.CustomInclude = pwd;

codegen -config cfg main_runtime_check.c main_runtime_check.h errorCheckExample -args 1 -o errorCheckExample_c -d codegen_c_exe
Code generation successful.

生成された実行可能ファイルを実行します。ユーティリティ関数 rtErrorWithMessageID でハードコードされているエラー メッセージが出力されることを確認します。

if isunix
    system('./errorCheckExample_c');
elseif ispc
    system('errorCheckExample_c.exe');
else
    disp('Platform is not supported');
end
Domain error. To compute complex results from real x, use 'sqrt(complex(x))'.
Error in sqrt (line 13)
./errorCheckExample_c: Aborted

C++ のライブラリと実行可能ファイルの生成

double のスカラー入力を受け入れる errorCheckExample の C++ ダイナミック リンク ライブラリを生成します。コード構成オブジェクトを使用して RuntimeChecks パラメーターを true に設定します。さらに、-d オプションを使用して、コード生成フォルダーに codegen_cpp_dll という名前を付けます。

cfg = coder.config('dll');
cfg.RuntimeChecks = true;
codegen -config cfg -lang:c++ errorCheckExample -args 1 -d codegen_cpp_dll -report
Code generation successful: To view the report, open('codegen_cpp_dll/html/report.mldatx')

コード生成レポートを開き、ファイル errorCheckExample.cpp を検査します。前のセクションで生成された C 関数と同様に、errorCheckExample は正の入力のみを受け入れます。負の入力に対しては、errorCheckExample はユーティリティ関数 rtErrorWithMessageID を呼び出します。ただし、この場合、ユーティリティ関数は std:runtime_error 例外をスローします。これを手書きの main 関数でキャッチして処理できます。

static void rtErrorWithMessageID(const char *b, const char *aFcnName,
                                 int aLineNum)
{
  std::stringstream outStream;
  ((outStream << "Domain error. To compute complex results from real x, use \'")
   << b)
      << "(complex(x))\'.";
  outStream << "\n";
  ((((outStream << "Error in ") << aFcnName) << " (line ") << aLineNum) << ")";
  throw std::runtime_error(outStream.str());
}

ライブラリ コードを生成する際に、コード ジェネレーターはメイン ファイルの例 main.h および main.c もビルド フォルダーの examples サブフォルダーに生成しています。C++ サポート ファイル main_runtime_check.hpp および main_runtime_check.cpp は、これらのサンプル ファイルを変更したものです。変更された main() 関数は、try-catch ブロックの内部の errorCheckExample(-4) を呼び出します。このブロックは例外をキャッチし、キャッチした例外に含まれているメッセージの前に "Caught excaption: " という文字列を付けて変更されたメッセージを出力します。

次のコマンドを実行して、変更されたメイン ファイルを使用する C++ 実行可能ファイルを生成します。コード生成フォルダーに codegen_cpp_exe という名前を付けます。実行可能ファイルに errorCheckExample_cpp という名前を付けます。

cfg = coder.config('exe');
cfg.RuntimeChecks = true;
cfg.CustomSource = 'main_runtime_check.cpp';
cfg.CustomInclude = pwd;

codegen -config cfg -lang:c++ main_runtime_check.cpp main_runtime_check.hpp errorCheckExample -args 1 -o errorCheckExample_cpp -d codegen_cpp_exe
Code generation successful.

生成された実行可能ファイルを実行します。変更されたエラー メッセージが出力されることを確認します。

if isunix
    system('./errorCheckExample_cpp');
elseif ispc
    system('errorCheckExample_cpp.exe');
else
    disp('Platform is not supported');
end
Caught exception: Domain error. To compute complex results from real x, use 'sqrt(complex(x))'.
Error in sqrt (line 13)

制限

スタンドアロン コードでの実行時エラーの検出とレポートには、次の制限があります。

  • エラー メッセージは英語のみです。

  • 一部のエラー チェックでは倍精度のサポートが必要になります。そのため、生成されたコードを実行するハードウェアで倍精度の演算がサポートされている必要があります。

  • プログラムが終了した場合、実行時スタックはエラー検出/報告ソフトウェアで表示されません。スタックを検査するには、デバッガーを接続してください。

  • 生成された C コードが終了した場合、割り当てられたメモリなどのリソースはエラー検出/報告ソフトウェアで解放されません。生成された C++ コードにはこの制限はありません。生成された C++ コードが終了した場合、割り当てられたメモリやその他のリソースが解放されます。

  • スタンドアロン コードでは、関数 error はエラーが発生したことを示すメッセージを表示します。error で指定されている実際のメッセージを確認するには、MEX 関数を生成して実行する必要があります。

  • スタンドアロン コードでは、関数 assert を複数の引数を指定して呼び出した場合、エラーは報告されず、実行も終了しません。たとえば assert(cond) のように単一の引数を指定して呼び出した場合は、cond が定数値 true でなければ、エラーが報告されて実行が終了します。

参考

| |

関連するトピック