Spec-Zone.ru › Octave 9

A.1.9 Вызов внешнего кода из Oct-файлов

Связать внешний код на C с Octave относительно просто, поскольку функции C можно без труда вызывать напрямую из C++. Возможная проблема заключается в том, что объявления внешних функций C может потребоваться явно определить для компилятора как функции C. Если объявления внешних функций C находятся в заголовочном файле foo.h, то для того, чтобы компилятор C++ воспринимал эти объявления как код C, следует использовать следующий приём:

#ifdef __cplusplus
extern "C"
{
#endif
#include "foo.h"
#ifdef __cplusplus
}  /* end extern "C" */
#endif

При вызове функций, реализованных на Fortran, необходимо учитывать некоторые особенности. Имена символов в Fortran нечувствительны к регистру, и в зависимости от используемого компилятора Fortran имена функций экспортируются либо полностью строчными, либо полностью заглавными буквами. Кроме того, некоторые компиляторы добавляют в конец имён экспортируемых функций ноль, одно или два подчёркивания "_". Это называется «искажением имён» (name-mangling).

В Octave предусмотрены макросы, позволяющие писать код, который автоматически учитывает искажение имён для ряда компиляторов Fortran. Это F77_FUNC и F77_FUNC_. Первый следует использовать для функций Fortran, имена которых не содержат подчёркиваний. Второй следует использовать для функций Fortran, имена которых содержат подчёркивания. Оба макроса принимают два аргумента: первый — имя функции Fortran строчными буквами, второй — то же имя функции Fortran заглавными буквами.

Помимо искажения имён, разные компиляторы используют различные соглашения о вызовах для некоторых типов. В Octave определены следующие макросы препроцессора, позволяющие писать код, совместимый с различными соглашениями о вызовах Fortran.

Обратите внимание, что мы не пытаемся обрабатывать функции Fortran: для них всегда используются обёртки-подпрограммы, а возвращаемое значение передаётся как дополнительный аргумент.

Используйте следующие макросы для передачи символьных строк из C в Fortran:

F77_CHAR_ARG(x)
  F77_CONST_CHAR_ARG(x)
  F77_CXX_STRING_ARG(x)
  F77_CHAR_ARG_LEN(l)
  F77_CHAR_ARG_DECL
  F77_CONST_CHAR_ARG_DECL
  F77_CHAR_ARG_LEN_DECL

Используйте следующие макросы для написания функций на языке C, принимающих символьные строки в стиле Fortran:

F77_CHAR_ARG_DEF(s, len)
  F77_CONST_CHAR_ARG_DEF(s, len)
  F77_CHAR_ARG_LEN_DEF(len)
  F77_CHAR_ARG_USE(s)
  F77_CHAR_ARG_LEN_USE(s, len)

Используйте следующие макросы для типов Fortran в коде C++:

F77_INT4

Эквивалент типа Fortran INTEGER*4

F77_DBLE

Эквивалент типа Fortran DOUBLE PRECISION

F77_REAL

Эквивалент типа Fortran REAL

F77_CMPLX

Эквивалент типа Fortran COMPLEX

F77_DBLE_CMPLX

Эквивалент типа Fortran DOUBLE COMPLEX

F77_LOGICAL

Эквивалент типа Fortran LOGICAL

F77_RET_T

Тип возвращаемого значения функции C++, действующей как подпрограмма Fortran.

Используйте следующие макросы для возврата из функций на языке C, которые должны действовать как подпрограммы Fortran. Макрос F77_NORETURN предназначен для использования в качестве последнего оператора такой функции, помеченной атрибутом "noreturn".

F77_RETURN(retval)
  F77_NORETURN(retval)

В коде Fortran следует использовать функцию XSTOPX вместо функции Fortran STOP. XSTOPX использует обработчик исключений Octave для явной обработки ошибок в коде Fortran. Обратите внимание, что в Octave предусмотрена собственная замена функции XERBLA из BLAS, использующая XSTOPX.

В следующем примере показано включение функции Fortran в oct-файл; обёртка на C++ выглядит так:

#include <octave/oct.h>
#include <octave/f77-fcn.h>

extern "C"
{
  F77_RET_T
  F77_FUNC (fortransub, FORTRANSUB)
    (const F77_INT&, F77_DBLE*, F77_CHAR_ARG_DECL F77_CHAR_ARG_LEN_DECL);
}

DEFUN_DLD (fortrandemo, args, , "Fortran Demo")
{
  if (args.length () != 1)
    print_usage ();

  NDArray a = args(0).array_value ();

  double *av = a.fortran_vec ();
  octave_idx_type na = a.numel ();

  OCTAVE_LOCAL_BUFFER (char, ctmp, 128);

  F77_FUNC (fortransub, FORTRANSUB)
            (na, av, ctmp F77_CHAR_ARG_LEN (128));

  return ovl (a, std::string (ctmp));
}

а функция Fortran — так:

subroutine fortransub (n, a, s)
      implicit none
      character*(*) s
      real*8 a(*)
      integer*4 i, n, ioerr
      do i = 1, n
        if (a(i) .eq. 0d0) then
          call xstopx ('fortransub: divide by zero')
        else
          a(i) = 1d0 / a(i)
        endif
      enddo
      write (unit = s, fmt = '(a,i3,a,a)', iostat = ioerr)
     $       'There are ', n,
     $       ' values in the input vector', char(0)
      if (ioerr .ne. 0) then
        call xstopx ('fortransub: error writing string')
      endif
      return
      end

В этом примере продемонстрированы большинство возможностей, необходимых для связывания с внешней функцией Fortran, включая передачу массивов и строк, а также обработку исключений. Для работы примера необходимо скомпилировать и файл Fortran, и файл C++.

mkoctfile fortrandemo.cc fortransub.f
[b, s] = fortrandemo (1:3)
⇒
  b = 1.00000   0.50000   0.33333
  s = There are   3 values in the input vector
[b, s] = fortrandemo (0:3)
error: fortrandemo: fortransub: divide by zero

© 1996–2026 The Octave Project Developers
Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies.
Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one.Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions.
https://docs.octave.org/v9.4.0/Calling-External-Code-from-Oct_002dFiles.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API