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编译器,函数名导出时要么全部使用小写字符,要么全部使用大写字符。此外,有些编译器不附加任何下划线、一个或两个下划线_这被称为“名称篡改”。

Octave提供的宏允许为许多不同的Fortran编译器编写自动处理时间篡改的代码。这些宏是F77_FUNCF77_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

使用以下宏编写接受fortran样式字符串的C语言函数:

  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)

对C++代码中的Fortran类型使用以下宏:

F77_INT4

等效于FortranINTEGER*4类型

广告
F77_DBLE

等效于FortranDOUBLE PRECISION类型

广告
F77_REAL

等效于FortranREAL类型

广告
F77_CMPLX

等效于FortranCOMPLEX类型

广告
F77_DBLE_CMPLX

等效于FortranDOUBLE COMPLEX类型

广告
F77_LOGICAL

等效于FortranLOGICAL类型

广告
F77_RET_T

C++函数的返回类型,其作用类似于Fortran子程序。

广告

使用以下宏从C语言函数返回,这些函数被认为与Fortran子程序类似。F77_NORETURN旨在用作已符号为的函数的最后一个语句"noreturn"属性

  F77_RETURN(retval)
  F77_NORETURN(retval)

底层Fortran代码应该使用XSTOPX函数来替换FortranSTOP作用XSTOPX使用Octave异常处理程序显式处理Fortran代码中的失败情况。请注意,Octave提供自己的替代品爆破 XERBLA函数,使用XSTOPX.

以下示例显示了在oct文件中包含Fortran函数,其中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

版权所有 © 2024-2025 Octave中文网

ICP备案/许可证号:黑ICP备2024030411号-2