S-Function Passing input array to c-function

16 views (last 30 days)
Dimitri
Dimitri on 16 Feb 2026 at 13:04
Answered: Tridib on 19 Feb 2026 at 5:17
Hello!
I’m trying to reproduce the example described in https://nl.mathworks.com/help/rtw/tlc/inlining-s-functions.html, but with a function that takes all the input arrays from the block. Here is my code:
wrapsfnc.c
#define S_FUNCTION_NAME wrapsfcn
#define S_FUNCTION_LEVEL 2
#include "simstruc.h"
extern void times_two(const real_T *inPtr, real_T *outPtr, const int_T numEls); /* Declare times_two as extern */
/*
* mdlInitializeSizes - initialize the sizes array
*/
static void mdlInitializeSizes(SimStruct *S)
{
ssSetNumSFcnParams(S, 0); // Number of expected parameters
if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {
return; // Parameter mismatch will be reported by Simulink
}
if (!ssSetNumInputPorts(S, 1)) return;
ssSetInputPortWidth(S, 0, DYNAMICALLY_SIZED);
ssSetInputPortDataType(S, 0, SS_DOUBLE);
ssSetInputPortDirectFeedThrough(S, 0, 1);
if (!ssSetNumOutputPorts(S, 1)) return;
ssSetOutputPortWidth(S, 0, DYNAMICALLY_SIZED);
ssSetOutputPortDataType(S, 0, SS_DOUBLE);
ssSetNumSampleTimes(S, 1);
ssSetOptions(S, 0);
}
/*
* mdlInitializeSampleTimes - indicate that this S-function runs
* at the rate of the source (driving block)
*/
static void mdlInitializeSampleTimes(SimStruct *S)
{
ssSetSampleTime(S, 0, INHERITED_SAMPLE_TIME);
ssSetOffsetTime(S, 0, 0.0);
}
/*
* mdlOutputs - compute the outputs by calling times_two, which
* resides in another module, times_two.c
*/
static void mdlOutputs(SimStruct *S, int_T tid)
{
const real_T *uPtrs = ssGetInputPortRealSignal(S, 0);
real_T *y = ssGetOutputPortRealSignal(S, 0);
const int_T width = ssGetOutputPortWidth(S, 0);
times_two(uPtrs, y, width); /* Call times_two in mdlOutputs */
}
/*
* mdlTerminate - called when the simulation is terminated.
*/
static void mdlTerminate(SimStruct *S)
{
// No termination needed
}
#ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX-file? */
#include "simulink.c" /* MEX-file interface mechanism */
#else
#include "cg_sfun.h" /* Code generation registration function */
#endif
times_two.c
#ifdef MATLAB_MEX_FILE
#include "tmwtypes.h"
#else
#include "rtwtypes.h"
#endif
void times_two(const real_T *inPtr, real_T *outPtr, const int_T numEls)
{
for (int_T i = 0; i < numEls; i++)
outPtr[i] = 2.0*inPtr[i];
}
for compiling, I've used a command
mex wrapsfcn.c times_two.c
The result of the running the Simulink model was quite weird:
To by-pass this problem, I've created a temporary array and copied-by-value the input array:
InputPtrsType uPtrs = ssGetInputPortSignalPtrs(S, 0); // instead of ssGetInputPortRealSignal(S, 0);
...
real_T dblTemp[width];
for(int_T i = 0; i < width; i++)
dblTemp[i] = *(real_T *)uPtrs[i];
times_two(dblTemp, y, width); /* Call times_two in mdlOutputs */
and the result was OK:
Could you please explain my initial error and why my by-pass solution finally worked?
Please find attached the simulink files in the Inlined.zip

Answers (1)

Tridib
Tridib ongeveer 7 uur ago
Dear @Dimitri,
Your first implementation read the input as a single contiguous real_T* using ssGetInputPortRealSignal, but you never told Simulink that the input elements are guaranteed to be contiguous. By default, RequiredContiguous is false, so the engine may provide a non‑contiguous layout, and indexing u[i] then walks arbitrary memory, hence the tiny “garbage” doubles you observed, which is a symptom of reading the wrong addresses. The “bypass” worked because ssGetInputPortSignalPtrs returns one pointer per element specifically for the non‑contiguous case, so dereferencing each uPtrs[i] accesses the correct element regardless of layout, producing the expected results.
Hope this helps!

Categories

Find more on Simulink Coder in Help Center and File Exchange

Products


Release

R2022a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!