# Лекция 8. Как вызвать функции, написанные на C/C++, из матлаба

### Белошапкин В.В.

Copyright © Красноярский государственный университет 2003

### Содержание

###

    Как вызвать функции, написанные на C/C++, из матлаба
     Задачи

      Как вызвать функции, написанные на C/C++, из матлаба

        При инсталляции Matlab необходимо установить Matlab C/C++ math. library.
    Затем нужно выполнить настройку скриптов матлаба с помощью команды mex -setup,
    которую можно вводить либо с консоли Matlab, либо с консоли Windows. Эту команду
    необходимо выполнять пользователю с правами администратора системы, поскольку при этом
    производятся записи в системные файлы. После этого можно приступать к написанию программы
    на языках C/C++ или Fortran, которую можно будет вызывать непосредственно из матлаба.
    В данной лекции рассматривается лишь связь программ на C/C++ с матлабом.
    Предположим, что необходимо написать программу на языке C вызов которой в командной строке
    matlab имеет вид [a b]=fun(d,e,f);. Функция fun должна получать три матрицы из матлаба
    и возвращать после работы две матрицы. Для решения поставленной задачи необходимо
    написать программу на C с любым количеством функций, но среди них обязательно должна
    быть функция с именем mexFunction. Эта функция играет такую же роль для наших целей,
    как функция main для консольных приложений. Функция mexFunction имеет всегда четыре аргумента.
    void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]);.
    При написании программ на языках C/C++ всегда необходимо включать заголовочный файл
    mex.h, который хранится в %MATLAB%\extern\include.   В файле matrix.h, подключаемом
    из mex.h,  определен тип  данных mxArray, который представляет в программах на языке
    Си матрицы матлаба.  Описание аргументов функции mexFunction:
    nlhs - число возвращаемых в матлаб матриц,
    plhs - массив адресов матриц (переменные типа mxArray), возвращаемых в матлаб,
    nrhs - число аргументов, переданных в функцию при вызове из матлаба,
    prhs - массив адресов матриц, переданных в функцию при вызове из матлаба.
    В заголовочном файле matrix.h описаны все функции, необходимые для работы с переменными
    типа mxArray. Приведу лишь наиболее часто употребляемые. Но прежде необходимо отметить,
    что ряд функций, которые использовались в консольных приложениях, нельзя использовать
    при вызове функций из матлаба. Это прежде всего функции, содержащиеся в зоголовочных
    файлах stdio.h и malloc.h. Вместо функции printf необходимо использовать функцию
    extern int mexPrintf(
        const char	*fmt,	/* printf style format */
        ...				/* any additional arguments */
        ); ,
    аргументы которой полностью аналогичны аргументам функции printf.
    Вместо функции malloc необходимо использовать функцию
    extern void *mxMalloc(
        size_t	n		/* number of bytes */
        );.
    Вместо функции free используется функция
    extern void mxFree(void *ptr);	/* pointer to memory to be freed */ и т.д.
    Для размещения в памяти новой переменной типа mxArray используется функция
    extern mxArray *mxCreateDoubleMatrix(int m, int n, mxComplexity flag);,
    где m - число строк матрицы, n - число столбцов, переменная flag принимает
    два значения: mxREAL - если матрица будет вещественной и mxCOMPLEX - если
    матрица будет комплексной. Чтобы получить число строк матрицы можно воспользоваться
    функцией
    extern int mxGetM(
        const mxArray *pa		/* pointer to array */
        );,
    а для получения числа столбцов функцией
    extern int mxGetN(
        const mxArray *pa		/* pointer to array */
        );.
    Для получения указателя на первый элемент массива, где хранится вещественная часть матрицы,
    используется функция
    extern double *mxGetPr(
        const mxArray *pa		/* pointer to array */
        );,
    а для мнимой части матрицы функция
    extern double *mxGetPi(
        const mxArray *pa		/* pointer to array */
        );.
    Вещественные и мнимые части матриц хранятся в одномерных массивах по строкам. Для того,
    чтобы получить номер элемента лежащего в заданой строке и заданном столбце можно
    воспользоваться функцией
    extern int mxCalcSingleSubscript(const mxArray *pa, int nsubs, const int *subs);,
    где nsubs - число элементов в массиве subs, subs[0]- номер строки, subs[1] - номер
    столбца.

    Назначить вещественный массив в качестве вещественной части матрицы можно функцией
    extern void mxSetPr(
        mxArray *pa,		/* pointer to array */
        double  *pr			/* real data array pointer */
        );,
    а для мнимой части функцией
    extern void mxSetPi(
        mxArray *pa,		/* pointer to array */
        double  *pr			/* imaginary data array pointer */
        );.

    Выполнить в программе на языке Си любую функцию матлаба можно с помощью функции
    extern int mexCallMATLAB(
        int		nlhs,			/* number of expected outputs */
        mxArray	*plhs[],		/* pointer array to outputs */
        int		nrhs,			/* number of inputs */
        mxArray	*prhs[],		/* pointer array to inputs */
        const char	*fcn_name		/* name of function to execute */
        ); .

    Много примеров mex-функций можно найти в директории матлаба %MATLAB%\extern\examples\mex.
    Самый простой из них содержится в файле mexfunction.c.
    Для компиляции нужно ввести команду mex mexfunction.c с консоли
    матлаба или windows.
    Если в программе нет ошибок и компиляция успешна Вы получите файл
    mexfunction.dll, который можно запускать из матлаба.

    /*=================================================================
    * mexfunction.c
    *
    * This example demonstrates how to use mexFunction. It returns
    * the number of elements for each input argument, providing the
    * function is called with the same number of output arguments
    * as input arguments.

    * This is a MEX-file for MATLAB.
    * Copyright 1984-2000 The MathWorks, Inc.
    * All rights reserved.
    *=================================================================*/
    /* $Revision: 1.5 $ */
    #include "mex.h"

    void
    mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
    {
    int i;

    /* Examine input (right-hand-side) arguments. */
    mexPrintf("\nThere are %d right-hand-side argument(s).", nrhs);
    for (i=0; i<nrhs; i++) {
    mexPrintf("\n\tInput Arg %i is of type:\t%s ",i,mxGetClassName(prhs[i]));
    }

    /* Examine output (left-hand-side) arguments. */
    mexPrintf("\n\nThere are %d left-hand-side argument(s).\n", nlhs);
    if (nlhs > nrhs)
    mexErrMsgTxt("Cannot specify more outputs than inputs.\n");
    for (i=0; i<nlhs; i++) {
    plhs[i]=mxCreateDoubleMatrix(1,1,mxREAL);
    *mxGetPr(plhs[i])=mxGetNumberOfElements(prhs[i]);
    }
    }

    Задачи Задача 1.
    Полиномы Эрмита вычисляются по формулам
    H(0,x)=1 H(1,x)=2*x H(k,x)=2*x*H(k-1,x) -2*(k-1)*H(k-2,x).
    Написать mexFunction для вычисления значений первых n+1 полиномов Эрмита для заданного
    значения x. Вызов в матлабе должен выглядеть примерно так h=Hermit(n,x), где
    h - вектор столбец из n+1 элемента.