Recherche…


Vérifier le nombre d'entrées / sorties dans un fichier MEX C ++

Dans cet exemple, nous allons écrire un programme de base qui vérifie le nombre d'entrées et de sorties passées à une fonction MEX.

Pour commencer, nous devons créer un fichier C ++ implémentant la "passerelle MEX". C'est la fonction exécutée lorsque le fichier est appelé depuis 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.");
    }
}

Tout d'abord, nous incluons l'en mex.h tête mex.h qui contient les définitions de toutes les fonctions et types de données requis pour fonctionner avec l'API MEX. Ensuite, nous implémentons la fonction mexFunction comme indiqué, où sa signature ne doit pas changer, indépendamment des entrées / sorties réellement utilisées. Les paramètres de la fonction sont les suivants:

  • nlhs : Nombre de sorties demandées.
  • *plhs[] : Tableau contenant toutes les sorties au format API MEX.
  • nrhs : Nombre d'entrées passées.
  • *prhs[] : Tableau contenant toutes les entrées au format API MEX.

Ensuite, nous vérifions le nombre d’arguments entrées / sorties, et si la validation échoue, une erreur est lancée avec la fonction mexErrMsgIdAndTxt (on attend un somename:iD identifiant de format somename:iD , un simple "ID" ne fonctionnera pas).


Une fois le fichier compilé en mex testinputs.cpp , la fonction peut être appelée dans MATLAB comme:

>> 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.

Entrez une chaîne, modifiez-la en C et affichez-la

Dans cet exemple, nous illustrons la manipulation de chaînes dans MATLAB MEX. Nous allons créer une fonction MEX qui accepte une chaîne en entrée de MATLAB, copier les données dans C-string, les modifier et les reconvertir en mxArray renvoyées du côté MATLAB.

L'objectif principal de cet exemple est de montrer comment les chaînes peuvent être converties en C / C ++ à partir de MATLAB et vice versa.

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);
}

Les fonctions pertinentes dans cet exemple sont les suivantes:

  • mxIsChar pour tester si un mxArray est de type mxCHAR .
  • mxArrayToString pour copier les données d'une chaîne mxArray dans un tampon char * .
  • mxCreateString pour créer une chaîne mxArray partir d'un caractère char* .

En guise de remarque, si vous voulez seulement lire la chaîne et ne pas la modifier, n'oubliez pas de la déclarer en tant que const char* pour la rapidité et la robustesse.


Enfin, une fois compilé, nous pouvons l'appeler depuis MATLAB comme:

>> mex stringIO.cpp

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

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

Passer une matrice 3D de MATLAB à C

Dans cet exemple, nous illustrons comment prendre une double matrice 3D de type réel à partir de MATLAB et la passer à un tableau C double* .

Les principaux objectifs de cet exemple montrent comment obtenir des données à partir de baies MATLAB MEX et mettre en évidence certains petits détails dans le stockage et la gestion de la 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;
}

Les concepts pertinents à prendre en compte:

  • Les matrices MATLAB sont toutes 1D en mémoire, quel que soit le nombre de dimensions utilisées dans MATLAB. Cela est également vrai pour la plupart (sinon la totalité) représentation de la matrice principale dans les bibliothèques C / C ++, ce qui permet une optimisation et une exécution plus rapide.

  • Vous devez copier explicitement les matrices de MATLAB vers C dans une boucle.

  • Les matrices MATLAB sont stockées dans l'ordre des colonnes, comme dans Fortran, mais C / C ++ et la plupart des langages modernes sont majeurs. Il est important de permuter la matrice d'entrée, sinon les données seront complètement différentes.

Les fonctions pertinentes dans cet exemple sont les suivantes:

  • mxIsDouble vérifie si l'entrée est de type double .
  • mxIsComplex vérifie si l'entrée est réelle ou imaginaire.
  • mxGetData renvoie un pointeur sur les données réelles du tableau d'entrée. NULL s'il n'y a pas de données réelles.
  • mxGetDimensions renvoie un pointeur sur un tableau mwSize , avec la taille de la dimension dans chaque index.

Passer une structure par noms de champs

Cet exemple montre comment lire des entrées de structure de différents types dans MATLAB et les transmettre à des variables de type équivalent C.

Bien qu'il soit possible et facile de comprendre à partir de l'exemple comment charger des champs par des nombres, cela est obtenu en comparant les noms de champs aux chaînes. Ainsi, les champs de la structure peuvent être adressés par leurs noms de champs et les variables peuvent être lues par 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);
    }
  }
}

La boucle sur i s'exécute sur tous les champs de la structure, tandis que les parties if(0==strcmp) comparent le nom du champ matlab à la chaîne donnée. S'il s'agit d'une correspondance, la valeur correspondante est extraite dans une variable C.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow