[Биография]      [Диссертация]     [Ссылки]     [Содержание библиотеки]     [Почта]

Создание MEX-файлов на C/C++

Источник:
users.kaluga.ru/webpublic/matlab/theme4_2.htm

Создание MEX–файлов на входном языке компилятора позволяет максимально использовать производительность компьютера, так как вы можете написать наиболее оптимальный код. Перед вами открываются все возможности языка C++ (например, создание классов), можно делать вставки на Ассемблере, при этом сохраняются возможности графического интерфейса MATLAB. Написание MEX–файлов “руками” оправдано для критичных по времени вычислений, например, статистические испытания объекта.

Для создания MEX–файлов на входном языке компилятора необходим непосредственно ANSI C/C++ или Fortran компилятор. Для возможности компиляции в среде MATLAB при его установке выбирать дополнительные компоненты MATLAB Compiler, C Math Library или C++ Math Library необязательно!

С помощью команды mex -setup в окне управления MATLAB осуществляется конфигурирование системы , если ещё этого не сделано:

» mex –setup

Все примеры будут рассмотрены для языка C/C++. Использовался компилятор MS VC++ 5.0.

Каждый MEX–файл включает следующие фрагменты кода:

Точка входа.

Каждый MEX–файл имеет точку входа — часть кода, с которой начинается выполнение программы. Такой точкой является функция mexFunction:

void mexFunction(
      int nlhs,
      mxArray *plhs[],
      int nrhs, 
      const mxArray *prhs[] 
      )
{
      // дальнейший код на C/C++ 
}

Переменные nlhs и nrhs содержат соответственно число выходных и входных переменных (аргументов). Элементами массивов plhs и prhs являются указатели на значения аргументов. Например, для выражения [T, X] = samefun(A, B, C) значения nlhs = 2, nrhs = 3.

Анализ аргументов.

Если есть вероятность некорректного ввода входных аргументов, то имеет смысл осуществить проверку на количество, размерность и тип входных аргументов, а также на количество выходных аргументов:

/* Проверка количества входных и выходных
аргументов */

if (nrhs != 2) // Если число аргументов входа не равно
двум, то завершить программу с сообщением
            mexErrMsgTxt("Two inputs required.");

if(nlhs != 1) // Если число аргументов выхода не равно 
одному, то завершить программу с сообщением
            mexErrMsgTxt("One output required.");

Для проверки соответствия типу аргументов входа используется ряд функций API MATLAB начинающихся префиксом mxIs, входным параметром которых является указатель на аргумент:

/* Проверить, что первый аргумент входа является
действительным числом. */

if( !mxIsNumeric(prhs[0]) // Вх. есть не число,
      || !mxIsDouble(prhs[0]) // или вх. есть не тип double,
      || mxIsComplex(prhs[0]) // или вх. комплексный,
      || mxGetN(prhs[0])*mxGetM(prhs[0]) !=1 // и это не скаляр…
      ) // то вывести сообщение с завершением программы.

      mexErrMsgTxt("Input x must be a scalar.");

Связывание с локальными переменными входных и выходных аргументов.

Что бы работать со значениями аргументов входа и выхода их необходимо связать с локальными переменными, для чего в общем случае используют функцию double * mxGetPr(mxArray * p). Так как указатели массива выхода plhs первоначально ничем не инициализированы, то нужно это сделать с помощью функций mxCreate, например:

Инициализируем plhs[0] матрицей действительных чисел 5х3:

plhs[0] = mxCreateDoubleMatrix(5, 3, mxREAL);

Теперь нужно связать локальные переменные с входом и выходом. В зависимости от типа аргумента в MATLAB API есть несколько функций, начинающихся с префикса mxGet:

double in_1; // скаляр
double * in_2, * out_1; // массивы (матрица)

/* Скаляр */
in_1 = mxGetScalar(prhs[0]); // вернуть первый элемент

/* Матрица */
int nrows, ncols;
nrows = mxGetM(prhs[1]); // вернуть число строк
ncols = mxGetN(prhs[1]); // вернуть число столбцов
in_2 = mxGetPr(prhs[1]); // вернуть указатель на входной массив
out_1 = mxGetPr(plhs[0]); // вернуть указатель на выходной массив

Теперь можно работать с локальными переменными.

Пример:

Имеем матрицу M = [1 2; 3 4; 5 6], тогда в массиве x они будут представлены следующим образом: x = (1, 3, 5, 2, 4, 6). Тогда M(i, j) = *( x + nrows*(j-1) + i - 1).

M(1, 2) = *( x + 3*(2-1) + 1 - 1) = *( x + 3) = 2

Для работы с массивами произвольной длины используют две основные функции:

const int * mxGetDimensions(const mxArray * prhs);
int mxGetNumberOfDimensions(const mxArray * prhs);

Тело программы.

Здесь расположен собственно код, ради которого создан MEX–файл. В этой части кода можно включить функции, классы и другие структуры. Все процедуры можно оформить наиболее оптимальным способом, что невозможно для MATLAB Compiler.

Пример вставки на языке Ассемблера:

double i;
int j;
i = mxGetScalar(prhs[0]);
j = int(i);

/* Открываем блок с помощью _asm – специфика MS Visual
C++ */
_asm
{
      mov eax, j; // копируем в расширенный (32 разрядный
регистр) общего назначения
      inc eax; // увеличиваем на 1
      mov j, eax; // присваиваем переменной j новое
значение

}
mexPrintf("%g\n", i);
mexPrintf("%d\n", j);

Выход.

При завершении подпрограммы (окончание блока mexFunction(...) {...}) в среду MATLAB возвращаются связанные с массивом plhs значения.

Заключение.

Были изложены основополагающие моменты по созданию MEX–файлов на C/C++. API MATLAB содержат множество функций для работы с mat–файлами, можно использовать функции API Compiler, и даже можно делать вставки на Ассемблере. Все эти потрясающие возможности MATLAB делают её системой математических вычислений, сравнимой по скорости с программами изначально написанными на языках Delphi, Fortran, C/C++, при этом значительно сокращается время разработки и отладки программ.