将外部 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 函数,而是始终为它们使用子程序包装器(subroutine wrapper),并将返回值作为额外的参数传递。
使用以下宏将字符串从 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等效于 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类似于 Fortran 子程序的 C++ 函数的返回类型。
使用以下宏从应当像 Fortran 子程序那样运行的 C 语言函数中返回。F77_NORETURN 旨在用作已被标记了 "noreturn" 属性的函数的最后一条语句。
F77_RETURN(retval) F77_NORETURN(retval)
底层的 Fortran 代码应使用 XSTOPX 函数来替代 Fortran 的 STOP 函数。XSTOPX 使用 Octave 的异常处理程序来显式地处理 Fortran 代码中的失败情况。请注意,Octave 提供了自己的替代 BLAS XERBLA 函数,该函数使用了 XSTOPX。
以下示例展示了在 oct-file 中包含 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.rwdata ();
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-2026 Octave中文网
ICP备案/许可证号:黑ICP备2024030411号-4