Generated banner for Matlab Upgrade Mex Ic
Generated logo for Matlab Upgrade Mex Ic

Matlab Upgrade Mex Ic

MathWorksOfficialCreated by MathWorks

  • Skill
  • Workflow
  • Software development
  • BSD-2-Clause
  • No issues found

From the author

Upgrade C, C++, and Fortran MEX source files from the Separate Complex (SC) API to the Interleaved Complex (IC) API. Use when converting mxGetPr/mxGetPi to mxGetComplexDoubles, migrating MEX files to -R2018a, adding MX_HAS_INTERLEAVED_COMPLEX guards for SC/IC guarded builds, or modernizing legacy MEX code that uses mxGetData/mxSetData/mxGetImagData/mxSetImagData. Covers C (.c), C++ (.cpp, .cxx), and Fortran (.F, .f90) MEX functions. Triggers on: interleaved complex, IC MEX, mex upgrade, mex migration, separate complex, mxGetPi, mxGetPr replacement, -R2018a, complex MEX, Fortran MEX, .F MEX file, C++ MEX, .cpp MEX file, MEX performance, MEX slow complex, MEX call overhead, improve MEX performance complex.
— the description by MathWorks

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

This skill provides a structured workflow to migrate MEX source files from the legacy Separate Complex (SC) API to the current Interleaved Complex (IC) API. It supports C, C++, and Fortran languages, offering options for either full IC conversion or SC/IC guarded builds that maintain compatibility with older MATLAB versions. The process includes pre-upgrade verification, iterative refactoring of data access patterns, build configuration, and verification testing.

What it does

  • Identifies legacy SC API calls like mxGetPr and mxGetPi in source code.
  • Provides refactoring steps to replace legacy accessors with IC-compatible alternatives.
  • Implements preprocessor guards for dual-mode SC/IC builds.
  • Offers guidance on handling complex data layouts in C, C++, and Fortran.
  • Generates verification test commands to ensure output consistency.
  • Includes documentation templates for updated MEX file headers.

When to use it

  • When migrating legacy MEX files to R2018a or later.
  • When you need to modernize MEX code using deprecated mxGetPr/mxGetPi patterns.
  • When you need to support both older and newer MATLAB versions using guarded builds.
  • When you want to transition from separate real/imaginary buffers to interleaved complex data.

Advantages

  • Enables compatibility with modern MATLAB Interleaved Complex API requirements.
  • Provides a systematic, step-by-step approach to minimize manual refactoring errors.
  • Supports flexible migration paths including in-place editing or new file creation.
  • Includes built-in verification steps to validate output correctness across build modes.

Usage examples

“Help me upgrade my legacy C MEX file to the Interleaved Complex API.”
The agent will initiate the 7-step migration workflow, starting with a scan of your file for SC API calls and asking for your preferred output strategy.
“I need my Fortran MEX file to work on both R2017b and R2018a.”
The agent will guide you through adding preprocessor guards to your .F file to enable SC/IC guarded builds.

Install

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/matlab/matlab-upgrade-mex-ic/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip matlab-upgrade-mex-ic.zip -d .agents/skills

Documentation by MathWorks

Upgrade MEX Files to Interleaved Complex API

Convert C, C++, and Fortran MEX source files from the Separate Complex (SC) API to the Interleaved Complex (IC) API, following the MathWorks upgrade workflow with guardrails for SC/IC guarded builds using MX_HAS_INTERLEAVED_COMPLEX, required vs recommended changes, and verification.

When to Use

  • User has a C, C++, or Fortran MEX file using mxGetPr/mxGetPi, mxGetData/mxGetImagData, or mxSetPr/mxSetPi

  • User wants to build with mex -R2018a

  • User asks about interleaved complex, IC MEX, or modernizing MEX code

  • User has legacy MEX code from File Exchange, GitHub, or pre-R2018a era

  • User has a C++ MEX file (.cpp, .cxx) using the C Matrix API (mxGetPr/mxGetPi, etc.)

  • User has a Fortran MEX file (.F, .f90) using mxGetPr/mxGetPi via %val() pointers

  • User reports a MEX function is slow on large complex arrays (call overhead, not loop)

  • User asks how to improve MEX performance for complex data

When NOT to Use

  • Writing a new MEX function from scratch — no conversion needed, but advise the user to use IC APIs (mxGetDoubles, mxGetComplexDoubles, etc.) from the start for better performance on complex data and modern, type-safe data access instead of legacy mxGetPr/mxGetPi

  • C++ MEX API (matlab::mex::Function) — different API entirely; this skill covers C++ files that use the C Matrix API (mex.h), not the MATLAB Data API for C++ and C++ Engine

  • MEX file already uses typed accessors (mxGetDoubles, mxGetComplexDoubles, etc.) — already IC-compatible, no conversion needed

Workflow

Follow these 7 steps in order. Do NOT skip steps.

Step 1: Pre-Upgrade Verification

Before changing anything, understand the current state:

  1. Read the source file completely

  2. Identify all SC API calls (see Key API Mappings)

  3. Note which data types the MEX handles (double, single, int32, etc.)

  4. Note whether it handles complex data (mxGetPi, mxIsComplex, mxCOMPLEX)

Report to the user:

  • Number of SC API calls found

  • Whether file processes complex numbers (complex arrays in SC mode incur deinterleave/re-interleave overhead)

  • Performance impact: If the file handles complex data, note that SC MEX calls incur O(n) deinterleave/re-interleave copies at the MATLAB boundary. For large arrays, IC conversion eliminates this overhead entirely (see Performance Benefits).

  • Any other issues noticed (missing error checking, etc.)

Step 2: Output File Decision

ASK the user before proceeding:

"Where should I write the converted code?

  • New file — creates a separate file (e.g., <name>_ic.c or <name>_dual.c), preserving the original untouched

  • Modify in place — edits the original file directly. Choose this if the file is under version control and you can revert if needed."

If user chooses new file, use these naming defaults (or a user-specified name):

  • IC-only: <name>_ic.c / <name>_ic.F

  • SC/IC guarded: <name>_dual.c / <name>_dual.F

If user chooses modify in place, confirm the file is recoverable (e.g., "This file is tracked by git — you can revert with git checkout <file> if needed."). Then edit the original directly.

Tell the user which file you're writing to and why.

Step 3: Decision Point — IC-Only or SC/IC Guarded?

What is "SC/IC guarded"? A single source file that uses #if MX_HAS_INTERLEAVED_COMPLEX preprocessor guards to compile under both the Separate Complex API (mex -R2017b) and the Interleaved Complex API (mex -R2018a). The compiler defines MX_HAS_INTERLEAVED_COMPLEX=1 in IC mode and 0 in SC mode, so the guards select the correct code path at build time.

ASK the user before proceeding:

"Do you need this MEX file to compile under both the old SC API and the new IC API?

  • SC/IC guarded — wraps code in #if MX_HAS_INTERLEAVED_COMPLEX / #else guards so the same source builds with both mex -R2017b file.c (SC mode) and mex -R2018a file.c (IC mode). Choose this if you support multiple MATLAB versions.

  • IC-only — converts fully to IC API. Requires mex -R2018a to build. Simpler code but only works on R2018a+."

If user chooses SC/IC guarded, use the #if MX_HAS_INTERLEAVED_COMPLEX preprocessor pattern:

C/C++ files:

#if MX_HAS_INTERLEAVED_COMPLEX
    /* IC code path */
    mxComplexDouble *pc = mxGetComplexDoubles(prhs[0]);
#else
    /* SC code path */
    double *pr = mxGetPr(prhs[0]);
    double *pi = mxGetPi(prhs[0]);
#endif

Fortran files (.F preprocessed source):

#if MX_HAS_INTERLEAVED_COMPLEX
      mwPointer mxGetComplexDoubles
      complex*16, pointer :: pc(:)
      call mxGetComplexDoubles(prhs(1), pc)
#else
      mwPointer mxGetPr, mxGetPi
      mwPointer pr, pi
      pr = mxGetPr(prhs(1))
      pi = mxGetPi(prhs(1))
#endif

Fortran note: SC/IC guarded Fortran files MUST use .F extension (uppercase) so the MEX compiler invokes the C preprocessor. The .f or .f90 extension skips preprocessing and #if guards will not work. For .f90 files that cannot use preprocessor guards, use IC-only conversion.

If user chooses IC-only, convert directly without guards.

Step 4: Iterative Refactoring

All legacy data-access APIs are REQUIRED to be converted for a complete IC upgrade. Convert every pattern in this table:

Legacy PatternReplacementReason
mxGetPi(arr) for data accessmxGetComplexDoubles(arr) + .imagDoes not exist in IC
mxSetPi(arr, ptr)mxSetComplexDoubles(arr, ptr)Does not exist in IC
mxGetImagData(arr)Type-specific complex accessorDoes not exist in IC
mxSetImagData(arr, ptr)Type-specific complex setterDoes not exist in IC
mxGetPi(arr) != NULL for complexity checkmxIsComplex(arr) — works in both SC and ICDoes not exist in IC
mxGetPr(arr)mxGetDoubles(arr)Wrong results on complex arrays in IC; untyped
mxSetPr(arr, ptr)mxSetDoubles(arr, ptr)Wrong results on complex arrays in IC; untyped
mxGetData(arr) + void* castType-specific accessor (mxGetDoubles, mxGetInt32s, etc.)Wrong results on complex arrays in IC; untyped
mxSetData(arr, ptr)Type-specific setter (mxSetDoubles, mxSetInt32s, etc.)Wrong results on complex arrays in IC; untyped

Why all REQUIRED? mxGetPr/mxGetData on complex arrays in IC mode return a pointer to interleaved data (real and imaginary interleaved) — iterating as if it were real-only gives wrong results silently. On real-only arrays they still work, but are untyped (void* or always double*). When upgrading to IC, convert everything in one pass for correctness and type safety.

See references/pitfalls.md for common conversion mistakes (complexity checks, output allocation, buffer sizing, Fortran interleaved layout).

Reducing Code Duplication in SC/IC Guarded Mode

In SC/IC guarded mode, minimize duplication by guarding only the accessor calls, not entire logic blocks.

C/C++ files:

/* Guard only the pointer acquisition — logic stays shared */
double *pr_in, *pr_out;

#if MX_HAS_INTERLEAVED_COMPLEX
    pr_in = mxGetDoubles(prhs[0]);
#else
    pr_in = mxGetPr(prhs[0]);
#endif

plhs[0] = mxCreateDoubleMatrix(m, n, mxREAL);

#if MX_HAS_INTERLEAVED_COMPLEX
    pr_out = mxGetDoubles(plhs[0]);
#else
    pr_out = mxGetPr(plhs[0]);
#endif

/* Shared logic — no duplication */
for (i = 0; i < numElements; i++) {
    pr_out[i] = pr_in[i] * factor;
}

Fortran files (.F):

c     Guard only the pointer acquisition
#if MX_HAS_INTERLEAVED_COMPLEX
      pr_in = mxGetDoubles(prhs(1))
#else
      pr_in = mxGetPr(prhs(1))
#endif

c     Shared logic — no duplication
      call mxCopyPtrToReal8(pr_in, data, numElements)
      do i = 1, numElements
          data(i) = data(i) * factor
      end do

For complex data, the layout differs between modes (interleaved struct vs separate arrays), so full #if/#else blocks around the logic are unavoidable.

Rule of thumb:

  • Real data paths — guard only the accessor, share the loop

  • Complex data paths — guard the entire block (different data layouts require different loop bodies). See references/api-mappings.md § "SC/IC Guarded Pattern" for full complex loop examples in C, C++, and Fortran.

See references/api-mappings.md for the complete function mapping table.

Step 5: Build

Provide the exact build commands (adjust extension for language):

% C/C++ files
mex -R2018a <filename>.c       % Explicit IC mode
mex -R2017b <filename>.c       % Explicit SC mode
mex <filename>.c               % Default (version-dependent)
% For C++: same flags with .cpp or .cxx extension
mex -R2018a <filename>.cpp     % Explicit IC mode

% Fortran files (.F with preprocessor guards)
mex -R2018a <filename>.F       % Explicit IC mode
mex -R2017b <filename>.F       % Explicit SC mode
mex <filename>.F               % Default (version-dependent)

If the file is SC/IC guarded, remind the user to test all three build modes: -R2017b (SC), -R2018a (IC), and default (no flag).

Fortran: Files must use .F (uppercase) extension for preprocessor guards to work. If the source is .f or .f90, rename to .F or .F90 when adding #if guards.

Step 6: Verify

Provide MATLAB test commands that compare the converted MEX against the original.

For IC-only conversions (separate source files):

%% Build original with SC, converted with IC
mex -R2017b originalFile.c -output func_sc    % Explicit SC build
mex -R2018a convertedFile_ic.c -output func_ic % Explicit IC build

%% Compare outputs
Z = complex(rand(4,4), rand(4,4));
assert(isequal(func_sc(Z), func_ic(Z)), 'Output mismatch!');

For SC/IC guarded files (same source, three build modes):

%% Build same source in all three modes
mex -R2017b convertedFile.c -output func_sc       % Explicit SC (forces separate complex)
mex -R2018a convertedFile.c -output func_ic       % Explicit IC (forces interleaved complex)
mex convertedFile.c -output func_default           % Default (no API flag)

%% Compare outputs — all three must match
Z = complex(rand(4,4), rand(4,4));
out_sc = func_sc(Z);
out_ic = func_ic(Z);
out_default = func_default(Z);
assert(isequal(out_sc, out_ic), 'SC vs IC mismatch!');
assert(isequal(out_sc, out_default), 'SC vs default mismatch!');

Always test with:

  • Complex inputs (if the MEX handles complex data)

  • Real inputs (if the MEX handles real data)

  • Edge cases: empty arrays, scalars, large arrays

  • All three build modes: -R2017b (SC), -R2018a (IC), and default (no flag)

  • The original source file still compiles with mex -R2017b (confirms it was not modified)

Step 7: Document

Add build information to the converted file's header comment:

/*
 * Compile (Interleaved Complex API, R2018a+):
 *   mex -R2018a filename.c
 *
 * Original (Separate Complex API):
 *   mex originalFilename.c
 *
 * API Migration:
 *   mxGetPr/mxGetPi -> mxGetComplexDoubles
 *   mxSetPr/mxSetPi -> mxSetComplexDoubles
 */

Performance Benefits of IC Conversion

IC conversion is not just API modernization — it delivers measurable performance gains for MEX functions that handle complex data.

Why IC Is Faster

Since R2018a, MATLAB stores complex arrays internally in interleaved format ([re0, im0, re1, im1, ...]). When a MEX function compiled with the SC API is called:

  1. On entry: MATLAB deinterleaves the input — splitting one contiguous buffer into two separate real/imag arrays. This is an O(n) copy.

  2. On exit: MATLAB re-interleaves the output — merging separate buffers back. Another O(n) copy.

For a 10M-element complex double array, that's ~80 MB per complex array crossing the boundary (N × 16 bytes). A MEX with one complex input and one complex output pays ~160 MB total; a MEX with three complex inputs pays ~240 MB on input alone.

IC MEX functions access data in MATLAB's native layout — zero copy at the boundary.

Additional Performance Advantages
  • Cache locality: z[i].real and z[i].imag are adjacent (same cache line). SC requires jumping between two arrays millions of elements apart.

  • Single memcpy for bulk copy: Duplicating a complex array is one memcpy(dst, src, n * sizeof(mxComplexDouble)) vs two separate copies.

  • FFTW/BLAS/LAPACK interop: IC layout is byte-for-byte compatible with fftw_complex, double _Complex (C99), and cuBLAS/cuFFT types — no pack/unpack needed.

  • SIMD-friendly: Compilers can emit packed-double instructions that load a full complex number in one operation.

When Performance Justifies IC Migration
ScenarioSpeedup Significance
Large complex arrays (>100K elements)High — boundary copy dominates
Frequent MEX calls in a loopHigh — copy overhead accumulates
MEX wraps FFTW/BLAS callsHigh — eliminates pack/unpack
Small arrays (<1K elements)Low — copy overhead negligible
Real-only data (no mxGetPi)None — no deinterleave occurs

Tell the user: "For your [N]-element complex array, the SC API forces MATLAB to copy ~[N×16/1e6] MB per complex array argument. With [K] complex arrays crossing the boundary, that's ~[K×N×16/1e6] MB per call. IC eliminates this entirely."

Benchmark Template

After conversion, offer this benchmark to quantify the speedup:

%% Benchmark SC vs IC MEX performance
N = 1e7;  % 10M complex elements
Z = randn(1,N) + 1i*randn(1,N);
numIter = 20;

% Build both versions
mex -R2017b originalFile.c -output func_sc
mex -R2018a convertedFile_ic.c -output func_ic

% Warmup
for k = 1:3, func_sc(Z); func_ic(Z); end

% Time SC
tSC = zeros(numIter,1);
for k = 1:numIter, tic; func_sc(Z); tSC(k) = toc; end

% Time IC
tIC = zeros(numIter,1);
for k = 1:numIter, tic; func_ic(Z); tIC(k) = toc; end

fprintf('SC median: %.2f ms\n', median(tSC)*1000);
fprintf('IC median: %.2f ms\n', median(tIC)*1000);
fprintf('Speedup: %.1fx\n', median(tSC)/median(tIC));
assert(isequal(func_sc(Z), func_ic(Z)), 'Output mismatch!');
Optimization Tips
  • Use mxDuplicateArray for in-place-style operations: plhs[0] = mxDuplicateArray(prhs[0]); z = mxGetComplexDoubles(plhs[0]); — then modify z[i] directly. Avoids manual allocation and lets MATLAB optimize the copy.

  • Single-pass loops: In IC mode, conjugation or scaling touches both .real and .imag in one loop iteration with perfect spatial locality.

  • Avoid unnecessary mxMalloc: Create output as mxCOMPLEX and write directly into the buffer from mxGetComplexDoubles — no intermediate allocation.

Key API Mappings

Summary of the most common conversions. Full table in references/api-mappings.md.

Complex Data Access
SC APIIC APIType
mxGetPr + mxGetPimxGetComplexDoublesRequired
mxSetPr + mxSetPimxSetComplexDoublesRequired
mxGetImagDataType-specific complex accessorRequired
mxSetImagDataType-specific complex setterRequired
mxGetPi(x) != NULLmxIsComplex(x)Required
SC APIIC APIStatus
mxGetPrmxGetDoublesNot recommended — replace
mxSetPrmxSetDoublesNot recommended — replace
mxGetDatamxGetDoubles/mxGetInt32s/etc.Not recommended — replace
mxSetDatamxSetDoubles/mxSetInt32s/etc.Not recommended — replace
Complex Data Types (IC mode)
mxComplexDouble  /* struct with .real and .imag (both double) */
mxComplexSingle  /* struct with .real and .imag (both float) */
mxComplexInt32   /* struct with .real and .imag (both int32_T) */

Conventions

  • Always ask whether to create a new file or modify in place before writing

  • Always explain the reason for each change (does not exist in IC, or wrong results on complex arrays / untyped)

  • Always ask whether to use SC/IC guarded mode or IC-only before converting

  • Always provide verification test commands

  • Use mxIsComplex() for complexity checks — never mxGetPi() != NULL. mxIsComplex works in both SC and IC modes, so it can be placed outside #if guards.

  • Buffer sizing in IC mode: mxGetElementSize() returns the full interleaved size (16 bytes for complex double). Do NOT multiply by 2.

  • File naming (when creating new file): _ic.c/_ic.cpp or _ic.F suffix for IC-only conversions; _dual.c/_dual.cpp/_dual.F for SC/IC guarded; or modify in place if user chooses

  • C89 compatibility (C files only): Declare variables at the top of each #if/#else block or at the top of the function. MEX compilers may enforce C89 rules where declarations must precede statements. C++ files do not have this restriction.

  • Fortran file extensions: Use .F (uppercase) for SC/IC guarded Fortran files so the C preprocessor processes #if MX_HAS_INTERLEAVED_COMPLEX guards. .f and .f90 do not invoke the preprocessor.

  • Fortran pointer handling: In Fortran MEX, data pointers are mwPointer integers passed via %val() to copy routines (mxCopyPtrToReal8, mxCopyPtrToComplex16). In IC mode, use mxGetComplexDoubles which returns an mwPointer to the interleaved buffer.

Common Mistakes

MistakeWhy It's WrongCorrect Approach
Modifying without askingUser may lose the working SC version if not under version controlAlways ask: new file or modify in place?
Leaving mxGetPr/mxGetData calls unchangedNot recommended by MathWorks in IC MEX functionsReplace with typed accessors (mxGetDoubles, mxGetInt32s, etc.)
numElements * mxGetElementSize(arr) * 2 for complex buffermxGetElementSize already returns 16 in IC modeUse numElements * mxGetElementSize(arr) without doubling
Using mxGetPi(arr) != NULL to check complexitymxGetPi doesn't exist in IC modeUse mxIsComplex(arr)
Converting without asking about compatibility needsUser may need the file to work on older MATLABAlways ask: IC-only or SC/IC guarded?
Not providing verification stepsSilent wrong answers are catastrophic in MEXAlways provide test commands comparing old vs new output

Copyright 2026 The MathWorks, Inc.


Files

references/pitfalls.md

IC Conversion Pitfalls

Common mistakes when converting C and Fortran MEX files from Separate Complex to Interleaved Complex API.

Pitfall 1: mxGetElementSize Doubling for Complex Data

The Problem

In SC mode, mxGetElementSize() returns 8 for a complex double array (just the real part size). Code often compensates:

/* SC code — multiplies by 2 for complex */
bufSize = numElements * mxGetElementSize(array) * 2;

In IC mode, mxGetElementSize() already returns 16 (the full mxComplexDouble struct size). Keeping the * 2 allocates double the needed memory.

Correct IC Code
/* IC code — mxGetElementSize already includes both parts */
size_t elementSize = mxGetElementSize(array);  /* Returns 16 for complex double */
size_t bufSize = numElements * elementSize;     /* No multiplication by 2 */
Size Reference
Array TypeSC mxGetElementSizeIC mxGetElementSize
real double88
complex double816
real single44
complex single48
real int3244
complex int3248

Pitfall 2: Complexity Checking with mxGetPi

The Problem

SC code commonly checks if an array is complex by testing if mxGetPi returns NULL:

/* SC pattern — BREAKS in IC mode */
if (mxGetPi(prhs[0]) != NULL) {
    /* Handle complex case */
}

In IC mode, mxGetPi does not exist. This will not compile.

Correct Approach (Works in Both Modes)
/* Correct — works in both SC and IC */
if (mxIsComplex(prhs[0])) {
    /* Handle complex case */
}

mxIsComplex() is available in all MATLAB versions and works correctly in both API modes.

Pitfall 3: Separate Buffer Allocation for Real and Imaginary

The Problem

SC code allocates separate buffers for real and imaginary parts:

/* SC pattern */
double *realBuf = (double *)mxMalloc(n * sizeof(double));
double *imagBuf = (double *)mxMalloc(n * sizeof(double));
/* Fill separately, then: */
mxSetPr(output, realBuf);
mxSetPi(output, imagBuf);
Correct IC Approach (Preferred)
/* IC pattern — create complex output, write directly into its buffer */
output = mxCreateDoubleMatrix(1, n, mxCOMPLEX);
mxComplexDouble *buf = mxGetComplexDoubles(output);
for (i = 0; i < n; i++) {
    buf[i].real = /* ... */;
    buf[i].imag = /* ... */;
}
Alternative (when you need a temporary buffer)
/* IC pattern — allocate separately, then attach */
mxComplexDouble *buf = (mxComplexDouble *)mxMalloc(n * sizeof(mxComplexDouble));
for (i = 0; i < n; i++) {
    buf[i].real = /* ... */;
    buf[i].imag = /* ... */;
}
output = mxCreateDoubleMatrix(0, 0, mxCOMPLEX);
mxSetComplexDoubles(output, buf);
mxSetM(output, 1);
mxSetN(output, n);

Pitfall 4: Accessing mxGetPr on Complex Arrays in IC Mode

The Problem

In SC mode, mxGetPr on a complex array returns the real part buffer. In IC mode, mxGetPr on a complex array returns a pointer to the interleaved data — the "real" values are interleaved with imaginary values, so iterating element-by-element gives wrong results.

Correct IC Approach

For complex arrays, always use mxGetComplexDoubles and access .real/.imag fields:

mxComplexDouble *pc = mxGetComplexDoubles(prhs[0]);
for (i = 0; i < n; i++) {
    double re = pc[i].real;
    double im = pc[i].imag;
}

For real-only arrays, mxGetDoubles (or even mxGetPr) works fine:

mxDouble *pr = mxGetDoubles(prhs[0]);  /* Real array only */

Pitfall 5: Creating Complex Output Arrays

The Problem

SC code creates a real array and then "promotes" it to complex by setting imaginary data:

/* SC pattern */
plhs[0] = mxCreateNumericArray(ndim, dims, mxDOUBLE_CLASS, mxREAL);
mxSetPr(plhs[0], realData);
mxSetImagData(plhs[0], imagData);  /* Promotes to complex */
Correct IC Approach

Create the array as complex from the start:

/* IC pattern */
plhs[0] = mxCreateNumericArray(ndim, dims, mxDOUBLE_CLASS, mxCOMPLEX);
mxComplexDouble *buf = (mxComplexDouble *)mxMalloc(n * sizeof(mxComplexDouble));
/* Fill buf[i].real and buf[i].imag */
mxSetComplexDoubles(plhs[0], buf);

Pitfall 6: Forgetting SC/IC Guards for Shared Code

The Problem

Converting to IC-only when the source is shared across teams or MATLAB versions. The IC-only version cannot be built without -R2018a.

When to Use SC/IC Guarded Pattern

Use #if MX_HAS_INTERLEAVED_COMPLEX when:

  • Source is on File Exchange or GitHub (users have different MATLAB versions)

  • Organization has mixed MATLAB installations

  • Code is part of a toolbox supporting multiple releases

Use IC-only when:

  • Team only uses R2018a or later

  • Internal code with controlled MATLAB version

  • User explicitly requests IC-only

Pitfall 7: Wrong Fortran File Extension for SC/IC Guards

The Problem

Fortran files with lowercase extensions (.f, .f90) do not invoke the C preprocessor. Adding #if MX_HAS_INTERLEAVED_COMPLEX guards to a .f file results in syntax errors — the compiler sees #if as invalid Fortran.

Correct Approach

Rename to uppercase extension before adding guards:

  • .f → .F

  • .f90 → .F90

The uppercase extension tells the MEX build system to invoke the C preprocessor first.

If renaming is not possible (e.g., build system constraints), use IC-only conversion without preprocessor guards.

Pitfall 8: Copying Complex Data Separately in Fortran IC Mode

The Problem

In SC Fortran MEX, complex data is accessed as two separate real arrays:

c     SC Fortran — separate real and imaginary
      call mxCopyPtrToReal8(mxGetPr(prhs(1)), xr, n)
      call mxCopyPtrToReal8(mxGetPi(prhs(1)), xi, n)

Naively replacing mxGetPr→mxGetDoubles and mxGetPi→mxGetComplexDoubles does NOT work for the imaginary part — mxGetComplexDoubles returns the full interleaved buffer, not just the imaginary part.

Correct IC Approach

Copy the entire interleaved buffer to a Fortran complex*16 array, then extract parts if needed:

c     IC Fortran — copy interleaved to complex*16
      complex*16 zdata(MAXN)
      call mxCopyPtrToComplex16(mxGetComplexDoubles(prhs(1)), zdata, n)
c     Now zdata(i) contains both real and imaginary parts
c     Access: dble(zdata(i)) for real, dimag(zdata(i)) for imaginary

Pitfall 9: Using %val() with IC Typed Accessors in Fortran

The Problem

Some SC Fortran MEX code passes pointers via %val() directly to computational subroutines:

c     SC Fortran — %val() pattern
      call myCompute(%val(mxGetPr(prhs(1))), n, result)

In IC mode, mxGetDoubles returns the same type (mwPointer), so %val() still works for real data. But for complex data, the interleaved layout means %val(mxGetComplexDoubles(...)) passes a pointer to {re, im, re, im, ...} — the receiving subroutine must expect interleaved data.

Correct Approach

For real data — %val() with typed accessors works unchanged:

      call myCompute(%val(mxGetDoubles(prhs(1))), n, result)

For complex data — copy to a Fortran complex*16 array first, then pass to the subroutine:

      call mxCopyPtrToComplex16(mxGetComplexDoubles(prhs(1)), zdata, n)
      call myComplexCompute(zdata, n, result)

Copyright 2026 The MathWorks, Inc.


Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
MathWorks
Publisher
MathWorks (Official)
Source
matlab/matlab-agentic-toolkit · skills-catalog/matlab-external-language-interfaces/matlab-upgrade-mex-ic · commit 2a7f215
Licence
BSD 2-Clause License (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE.md)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by MathWorks.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download matlab-upgrade-mex-ic.zip