Ricerca…


Controllare il numero di ingressi / uscite in un file MEX C ++

In questo esempio scriveremo un programma di base che controlla il numero di input e output passati a una funzione MEX.

Come punto di partenza, dobbiamo creare un file C ++ che implementa il "gateway MEX". Questa è la funzione eseguita quando il file viene chiamato da MATLAB.

testinputs.cpp

// MathWorks provided header file
#include "mex.h"

// gateway function
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    // This function will error if number of inputs its not 3 or 4
    // This function will error if number of outputs is more than 1

    // Check inputs:
    if (nrhs < 3 || nrhs > 4) {
        mexErrMsgIdAndTxt("Testinputs:ErrorIdIn",
            "Invalid number of inputs to MEX file.");
    }

    // Check outputs:
    if (nlhs > 1) {
        mexErrMsgIdAndTxt("Testinputs:ErrorIdOut",
                "Invalid number of outputs to MEX file.");
    }
}

Innanzitutto, includiamo l'intestazione mex.h che contiene le definizioni di tutte le funzioni e tipi di dati richiesti per funzionare con l'API MEX. Quindi implementiamo la funzione mexFunction come mostrato, dove la sua firma non deve cambiare, indipendentemente dagli input / output effettivamente utilizzati. I parametri della funzione sono i seguenti:

  • nlhs : numero di uscite richieste.
  • *plhs[] : Array che contiene tutti gli output nel formato API MEX.
  • nrhs : numero di input passati.
  • *prhs[] : Array che contiene tutti gli input nel formato API MEX.

Successivamente, controlliamo il numero di argomenti input / output, e se la validazione fallisce, viene generato un errore usando la funzione mexErrMsgIdAndTxt (si aspetta somename:iD identificatore di formato somename:iD , un semplice "ID" non funzionerà).


Una volta che il file è stato compilato come mex testinputs.cpp , la funzione può essere chiamata in MATLAB come:

>> testinputs(2,3)
Error using testinputs. Invalid number of inputs to MEX file.

>> testinputs(2,3,5)

>> [~,~] = testinputs(2,3,3)
Error using testinputs. Invalid number of outputs to MEX file.

Inserisci una stringa, modificala in C e stampala

In questo esempio, illustriamo la manipolazione delle stringhe in MATLAB MEX. Creeremo una funzione MEX che accetta una stringa come input da MATLAB, copia i dati in C-string, li modifica e li converte in mxArray restituito al lato MATLAB.

L'obiettivo principale di questo esempio è mostrare come le stringhe possono essere convertite in C / C ++ da MATLAB e viceversa.

stringIO.cpp

#include "mex.h"
#include <cstring>

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    // check number of arguments
    if (nrhs != 1 || nlhs > 1) {
        mexErrMsgIdAndTxt("StringIO:WrongNumArgs", "Wrong number of arguments.");
    }

    // check if input is a string
    if (mxIsChar(prhs[0])) {
        mexErrMsgIdAndTxt("StringIO:TypeError", "Input is not a string");
    }

    // copy characters data from mxArray to a C-style string (null-terminated)
    char *str = mxArrayToString(prhs[0]);

    // manipulate the string in some way
    if (strcmp("theOneString", str) == 0) {
        str[0] = 'T';  // capitalize first letter
    } else {
        str[0] = ' ';  // do something else?
    }

    // return the new modified string
    plhs[0] = mxCreateString(str);

    // free allocated memory
    mxFree(str);
}

Le funzioni rilevanti in questo esempio sono:

  • mxIsChar per verificare se un mxArray è di tipo mxCHAR .
  • mxArrayToString per copiare i dati di una stringa mxArray in un buffer char * .
  • mxCreateString per creare una stringa mxArray da un char* .

Come nota a margine, se si desidera solo leggere la stringa e non modificarla, ricordarsi di dichiararla come const char* per velocità e robustezza.


Infine, una volta compilato possiamo chiamarlo da MATLAB come:

>> mex stringIO.cpp

>> strOut = stringIO('theOneString')
strOut = 
TheOneString

>> strOut = stringIO('somethingelse')
strOut=
omethingelse

Passa una matrice 3D da MATLAB a C

In questo esempio illustriamo come prendere una doppia matrice 3D di tipo reale da MATLAB e passarla a un double* array C double* .

Gli obiettivi principali di questo esempio sono mostrare come ottenere dati dagli array MATLAB MEX e mettere in evidenza alcuni piccoli dettagli nell'archiviazione e gestione della matrice.

matrixIn.cpp

#include "mex.h"

void mexFunction(int  nlhs , mxArray *plhs[],
        int nrhs, mxArray const *prhs[]){
   // check amount of inputs
   if (nrhs!=1) {
        mexErrMsgIdAndTxt("matrixIn:InvalidInput", "Invalid number of inputs to MEX file.");
    }
   
   // check type of input
   if( !mxIsDouble(prhs[0]) || mxIsComplex(prhs[0])){
        mexErrMsgIdAndTxt("matrixIn:InvalidType",  "Input matrix must be a double, non-complex array.");
   }
   
   // extract the data
   double const * const matrixAux= static_cast<double const *>(mxGetData(prhs[0]));

   // Get matrix size
   const mwSize *sizeInputMatrix= mxGetDimensions(prhs[0]);

   // allocate array in C. Note: its 1D array, not 3D even if our input is 3D
   double*  matrixInC= (double*)malloc(sizeInputMatrix[0] *sizeInputMatrix[1] *sizeInputMatrix[2]* sizeof(double));

  
   // MATLAB is column major, not row major (as C). We need to reorder the numbers
   // Basically permutes dimensions   

   // NOTE: the ordering of the loops is optimized for fastest memory access! 
   // This improves the speed in about 300% 

    const int size0 = sizeInputMatrix[0]; // Const makes compiler optimization kick in
    const int size1 = sizeInputMatrix[1];
    const int size2 = sizeInputMatrix[2];
    
    for (int j = 0; j < size2; j++)
    {
        int jOffset = j*size0*size1; // this saves re-computation time
        for (int k = 0; k < size0; k++)
        {
            int kOffset = k*size1; // this saves re-computation time
            for (int i = 0; i < size1; i++)
            {
                int iOffset = i*size0; 
                matrixInC[i + jOffset + kOffset] = matrixAux[iOffset + jOffset + k];
            }
        }
    }

    // we are done!

    // Use your C matrix here

    // free memory
    free(matrixInC);
    return;
}

I concetti rilevanti di cui essere a conoscenza:

  • Le matrici MATLAB sono tutte 1D in memoria, indipendentemente dal numero di dimensioni che hanno quando vengono utilizzate in MATLAB. Questo vale anche per la maggior parte (se non tutti) la rappresentazione della matrice principale nelle librerie C / C ++, poiché consente l'ottimizzazione e un'esecuzione più rapida.

  • È necessario copiare esplicitamente le matrici da MATLAB a C in un ciclo.

  • Le matrici MATLAB sono archiviate nell'ordine delle colonne, come in Fortran, ma C / C ++ e le lingue più moderne sono le righe maggiori. È importante permutare la matrice di input, altrimenti i dati appariranno completamente diversi.

Le funzioni rilevanti in questo esempio sono:

  • mxIsDouble controlla se l'input è di tipo double .
  • mxIsComplex verifica se l'input è reale o immaginario.
  • mxGetData restituisce un puntatore ai dati reali nell'array di input. NULL se non ci sono dati reali.
  • mxGetDimensions restituisce un puntatore a un array mwSize , con la dimensione della dimensione in ogni indice.

Passare una struttura per nome di campo

Questo esempio illustra come leggere le voci struct di tipo vario da MATLAB e passarlo a variabili di tipo C equivalenti.

Mentre è possibile e facile capire dall'esempio come caricare i campi in base ai numeri, è qui ottenuto confrontando i nomi dei campi con le stringhe. Quindi i campi struct possono essere indirizzati con i loro nomi di campo e le variabili in esso possono essere letti da C.

structIn.c

#include "mex.h"
#include <string.h> // strcmp


void mexFunction (int nlhs, mxArray *plhs[],
                  int nrhs, const mxArray *prhs[])
{
  // helpers
  double* double_ptr;
  unsigned int i; // loop variable
  
  // to be read variables
  bool optimal;
  int randomseed;
  unsigned int desiredNodes;

  if (!mxIsStruct(prhs[0])) {
    mexErrMsgTxt("First argument has to be a parameter struct!");
  }
  for (i=0; i<mxGetNumberOfFields(prhs[0]); i++) {
    if (0==strcmp(mxGetFieldNameByNumber(prhs[0],i),"randomseed")) {
      mxArray *p = mxGetFieldByNumber(prhs[0],0,i);
      randomseed = *mxGetPr(p);
    }
    if (0==strcmp(mxGetFieldNameByNumber(prhs[0],i),"optimal")) {
      mxArray *p = mxGetFieldByNumber(prhs[0],0,i);
      optimal = (bool)*mxGetPr(p);
    }
    if (0==strcmp(mxGetFieldNameByNumber(prhs[0],i),"numNodes")) {
      mxArray *p = mxGetFieldByNumber(prhs[0],0,i);
      desiredNodes = *mxGetPr(p);
    }
  }
}

Il ciclo su i gira su ogni campo nella struttura specificata, mentre le parti if(0==strcmp) confrontano il nome del campo MATLAB con la stringa data. Se è una corrispondenza, il valore corrispondente viene estratto in una variabile C.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow