Generate Standalone C/C++ Code That Detects and Reports Run-Time Errors
During development, before you generate C/C++ code, it is a best practice to test the generated code by running the MEX version of your algorithm. However, some errors occur only on the target hardware. To detect these errors, generate standalone libraries and executables that detect and report run-time errors, such as out-of-bounds array indexing.
By default, run-time error detection is disabled for standalone libraries and executables. To enable run-time error detection and reporting for standalone libraries and executables:
At the command line, use the code configuration property
RuntimeChecks
.cfg = coder.config('lib'); % or 'dll' or 'exe' cfg.RuntimeChecks = true; codegen -config cfg myfunction
In the MATLAB® Coder™ app, in the project settings dialog box, on the Debugging pane, select the Generate run-time error checks check box.
Run-time error detection can affect the performance of the generated code. If performance is a consideration for your application, do not generate production code with run-time error detection enabled.
Generated C Code vs. Generated C++ Code
If your target language is C, the generated code uses fprintf
to
write error messages to stderr
. Then, the code uses
abort
to terminate the application. If fprintf
and
abort
are not available, you must provide them. The
abort
function abruptly terminates the program. If your system supports
signals, you can catch the abort signal (SIGABRT
) so that you can control
the program termination.
If your target language is C++, the generated code throws
std::runtime_error
exceptions for the run-time errors. When you call
the generated C++ entry-point functions, you can catch and handle these exceptions by using
a try
-catch
block in your external C++ code.
However, for run-time error checks inside parallel regions (either parfor
loops or automatically parallelized for
loops), the
generated C++ code does not throw an exception. In such situations, the generated code uses
fprintf
to write error messages to stderr
, and then
uses abort
to terminate the application. To learn more about automatic
parallelization, see Automatically Parallelize for Loops in Generated Code.
Example: Compare Generated C and C++ Code That Include Run-Time Checks
In this example, you compare the run-time behavior of generated C and C++ code for a MATLAB® function that calculates the square root of its input argument. The generated code can accept only nonnegative real values and produces a run-time error for negative inputs:
The generated C code uses
fprintf
to write the error message tostderr
. Then, the code usesabort
to terminate the application.The generated C++ code throws a
std::runtime_error
exception for this run-time error. In the C++ main function that you write to call the generated function, you catch and handle this exception by using atry
-catch
block.
Define MATLAB Function
Define the MATLAB function errorCheckExample
in a separate file. This function calculates the square root of its input argument:
type errorCheckExample
function y = errorCheckExample(x) y = sqrt(x); end
Generate C Library and Executable
Generate a dynamically linked C library for errorCheckExample
that accepts a double scalar input. Use a code configuration object with the RuntimeChecks
parameter set to true
. Also, use the -d
option to name the code generation folder as 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')
Open the code generation report and inspect the file errorCheckExample.c
. The C function generated for your MATLAB function has the signature double errorCheckExample(double x)
. To calculate the square root, errorCheckExample
invokes the sqrt
library function which calculates only real square roots. So, errorCheckExample
can accept only positive inputs. For negative inputs, errorCheckExample
calls the generated utility function rtErrorWithMessageID
that uses fprintf
to write an error message to stderr
and then uses abort
to terminate the application.
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(); }
When generating library code, the code generator also produces example main files main.h
and main.c
in the examples
subfolder of the build folder. The supporting C files main_runtime_check.h
and main_runtime_check.c
are modified versions of these example files. The modified main
function invokes errorCheckExample(-4)
, which produces a run-time error.
Run these commands to generate a C executable using the modified main files. Name the code generation folder codegen_c_exe
. Name the executable file errorCheckExample_c
by using the -o
option with the codegen
command.
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.
Run the generated executable. Observe that it prints the error message that is hard-coded in the utility function 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
Generate C++ Library and Executable
Generate a dynamically linked C++ library for errorCheckExample
that accepts a scalar double input. Use a code configuration object with the RuntimeChecks
parameter set to true
. Also, use the -d
option to name the code generation folder as 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')
Open the code generation report and inspect the file errorCheckExample.cpp
. Similar to the C function generated in the previous section, errorCheckExample
can accept only positive inputs. For negative inputs, errorCheckExample
calls the utility function rtErrorWithMessageID
. But in this case, the utility function throws a std:runtime_error
exception that you can catch and handle in your hand-written main
function.
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()); }
When generating library code, the code generator also produces example main files main.h
and main.c
in the examples
subfolder of the build folder. The supporting C++ files main_runtime_check.hpp
and main_runtime_check.cpp
are modified versions of these example files. The modified main()
function invokes errorCheckExample(-4)
inside a try-catch
block. The block catches the exception and prints a modified message by prepending the string "Caught excaption: "
to the message that the caught exception contains.
Run these commands to generate a C++ executable using the modified main files. Name the code generation folder codegen_cpp_exe
. Name the executable file 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.
Run the generated executable. Observe that it prints the modified error message.
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)
Limitations
Run-time error detection and reporting in standalone code has these limitations:
Error messages are in English only.
Some error checks require double-precision support. Therefore, the hardware on which the generated code runs must support double-precision operations.
If the program terminates, the error detection and reporting software does not display the run-time stack. To inspect the stack, attach a debugger.
If the generated C code terminates, the error detection and reporting software does not release resources, such as allocated memory. The generated C++ code does not have this limitation. If the generated C++ code terminates, allocated memory and other resources are released.
In standalone code, the function
error
displays a message that indicates that an error occurred. To see the actual message specified byerror
, you must generate and run a MEX function.In standalone code, if called with more than one argument, the function
assert
does not report an error and does not terminate execution. If called with a single argument, for example,assert(cond)
, ifcond
is not a constanttrue
value, reports an error and terminates execution.
See Also
codegen
| coder.CodeConfig
| coder.EmbeddedCodeConfig