Szukaj…


Sprawdź liczbę wejść / wyjść w pliku CEX MEX

W tym przykładzie napiszemy podstawowy program, który sprawdza liczbę wejść i wyjść przekazanych do funkcji MEX.

Na początek musimy utworzyć plik C ++ implementujący „bramę MEX”. Jest to funkcja wykonywana, gdy plik jest wywoływany z 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.");
    }
}

Najpierw mex.h nagłówek mex.h który zawiera definicje wszystkich wymaganych funkcji i typów danych do pracy z MEX API. Następnie implementujemy funkcję mexFunction jak pokazano, gdzie jej podpis nie może się zmienić, niezależnie od faktycznie używanych wejść / wyjść. Parametry funkcji są następujące:

  • nlhs : liczba żądanych wyników.
  • *plhs[] : Tablica zawierająca wszystkie dane wyjściowe w formacie MEX API.
  • nrhs : liczba przekazanych danych wejściowych.
  • *prhs[] : Tablica zawierająca wszystkie dane wejściowe w formacie MEX API.

Następnie sprawdzamy liczbę argumentów wejścia / wyjścia, a jeśli sprawdzanie poprawności się nie powiedzie, za pomocą funkcji mexErrMsgIdAndTxt jest błąd (oczekuje on mexErrMsgIdAndTxt somename:iD formatu somename:iD , prosty „ID” nie zadziała).


Po skompilowaniu pliku jako mex testinputs.cpp , funkcję można wywołać w MATLAB jako:

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

Wprowadź ciąg, zmodyfikuj go w C i wyślij go

W tym przykładzie przedstawiamy manipulację ciągiem znaków w MATLAB MEX. Utworzymy funkcję MEX, która akceptuje ciąg jako dane wejściowe z MATLAB, kopiuje dane do ciągu C, modyfikuje je i konwertuje z powrotem na mxArray zwrócone po stronie MATLAB.

Głównym celem tego przykładu jest pokazanie, w jaki sposób ciągi znaków można przekonwertować do C / C ++ z MATLAB i odwrotnie.

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

Odpowiednie funkcje w tym przykładzie to:

  • mxIsChar aby sprawdzić, czy mxArray jest typu mxCHAR .
  • mxArrayToString aby skopiować dane ciągu mxArray do bufora char * .
  • mxCreateString aby utworzyć ciąg mxArray z char* .

Na marginesie, jeśli chcesz tylko czytać ciąg, a nie go modyfikować, pamiętaj, aby zadeklarować go jako const char* dla szybkości i niezawodności.


Wreszcie po skompilowaniu możemy wywołać go z MATLAB jako:

>> mex stringIO.cpp

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

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

Przekaż matrycę 3D z MATLAB do C.

W tym przykładzie pokazujemy, jak pobrać podwójną macierz 3D typu rzeczywistego z MATLAB i przekazać ją do tablicy C double* .

Głównym celem tego przykładu jest pokazanie, jak uzyskać dane z tablic MATLAB MEX oraz zwrócić uwagę na małe szczegóły dotyczące przechowywania i obsługi matrycy.

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

Istotne pojęcia, o których należy pamiętać:

  • Matryce MATLAB są w pamięci 1D, bez względu na to, ile wymiarów mają, gdy są używane w MATLAB. Dotyczy to również większości (jeśli nie wszystkich) reprezentacji macierzy głównej w bibliotekach C / C ++, ponieważ pozwala to na optymalizację i szybsze wykonanie.

  • Musisz jawnie skopiować macierze z MATLAB do C w pętli.

  • Matryce MATLAB są przechowywane w porządku głównym kolumny, podobnie jak w Fortran, ale C / C ++ i większość współczesnych języków jest rzędem głównym. Ważne jest, aby permutować macierz wejściową, w przeciwnym razie dane będą wyglądać zupełnie inaczej.

Odpowiednimi funkcjami w tym przykładzie są:

  • mxIsDouble sprawdza, czy dane wejściowe są typu double .
  • mxIsComplex sprawdza, czy dane wejściowe są rzeczywiste, czy wymyślone.
  • mxGetData zwraca wskaźnik do rzeczywistych danych w tablicy wejściowej. NULL jeśli nie ma prawdziwych danych.
  • mxGetDimensions zwraca wskaźnik do tablicy mwSize , z rozmiarem wymiaru w każdym indeksie.

Przekazywanie struktury według nazw pól

Ten przykład ilustruje, jak czytać wpisy struktur różnego typu z MATLAB i przekazywać je do zmiennych typu równoważnego C.

O ile na przykład można ładować pola według liczb, to jest to możliwe poprzez porównanie nazw pól z ciągami znaków. W ten sposób pola struct mogą być adresowane przez ich nazwy pól, a zmienne mogą być odczytywane przez 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);
    }
  }
}

Pętla nad i biegnie przez każde pole w podanej strukturze, podczas gdy części if(0==strcmp) porównują nazwę pola if(0==strcmp) z podanym łańcuchem. Jeśli jest to dopasowanie, odpowiednia wartość jest wyodrębniana do zmiennej C.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow