Fortran 虚拟过程中的接口不匹配';f';将函数传递给子例程时

Fortran 虚拟过程中的接口不匹配';f';将函数传递给子例程时,fortran,fortran90,Fortran,Fortran90,我试图编写一个具有两个参数的子程序(用于最小化): 任意长度的数组x 一种函数f,它接受该长度的数组并返回标量 示例模块: module foo contains subroutine solve(x, f) real, dimension(:), intent(inout) :: x interface real pure function f(y) import x real, dimension(size(x)), i

我试图编写一个具有两个参数的子程序(用于最小化):

  • 任意长度的数组
    x
  • 一种函数
    f
    ,它接受该长度的数组并返回标量
示例模块:

module foo

contains

  subroutine solve(x, f)
    real, dimension(:), intent(inout) :: x
    interface
      real pure function f(y)
        import x
        real, dimension(size(x)), intent(in) :: y
      end function
    end interface

    print *, x
    print *, f(x)
  end subroutine

end module
测试程序:

use foo

real, dimension(2) :: x = [1.0, 2.0]

call solve(x, g)

contains

  real pure function g(y)
    real, dimension(2), intent(in) :: y

    g = sum(y)
  end function

end
gfortran在以下情况下失败:

call solve(x, g)
              1
Error: Interface mismatch in dummy procedure 'f' at (1): Shape mismatch in dimension 1 of argument 'y'
如果我更改
size(x)=>2
,那么它可以很好地编译(并运行)。如果我更改
:=>2,它也可以正常工作。但这两种解决方案都不能满足我的需求

有什么办法可以做到这一点吗

那么:

interface
  real pure function f(y)
    real, dimension(:), intent(in) :: y
  end function
end interface

当您将
solve
参数传递给函数时,将自动传递数组的大小。您不需要将此部分作为界面的一部分。

您有解决方案,但它值得一个解释。。。如果伪参数有一个显式接口(这里就是这样),那么就要求作为实际参数传递的过程的特征必须与伪参数的特征相匹配,除了纯粹性和基本本质之外。程序的特性包括其伪参数的特性,以及其他特性

伪参数的特征包括其形状等。如果该形状不是一个常数表达式,则特征包括“表达式中实体的精确依赖性”

伪参数
f
的接口块声明数组的大小为
size(x)
。x是一个与主机相关的假定形状变量-其大小在运行时可能会有所不同,因此
size(x)
不是一个常量。因此,表达式及其实体成为伪参数的特征

模块过程
g
声明数组的大小为
2
。这显然是一个常数

不管f伪参数大小的非常量表达式的值是多少,这些数组大小特征(某种表达式与常量)都不匹配,因此会出现错误


用常数2替换
SIZE(x)
时,特征明显匹配。当您将假定的形状
x
更改为常量大小2时,那么
size(x)
将成为值2的常量表达式-因为它是常量表达式,所有相关的都是它的值-因此两个参数的特征将匹配。当您将
f
的伪参数和
g
的伪参数都更改为假定形状
(:)
,则特征匹配。

如果您希望获得在您的解决方案注释中指出的安全性,您应该使用
-fcheck=bounds
,编译器将为假定和延迟的形状数组生成运行时检查。有关
-fcheck
的更多信息,请参阅gfortran手册页。但是,您将失去一些速度。

下面是一个示例,演示如何传递可分配数组

一些提示:

  • 使用模块避免繁琐的接口
  • 将数组传递给实际函数时,添加额外的矩阵大小信息。例如
    f(y,sizeinfo)
    以便在实际函数中可以正确声明输入矩阵的大小。可分配数组可以传递给子例程
    solve
    ,因此可以使用子例程
    solve
    中的大小(mat)获得大小
因此,更正后的版本如下所示:

module foo

contains

  subroutine solve(x, f)
    real, dimension(:), intent(inout) :: x
    real,external::f
        integer::sizeinfo

    print *,'x=', x
    sizeinfo = size(x)
    print *, 'f(x)=',f(x,sizeinfo)
  end subroutine

    real function g(y,sizeinfo)
    integer::sizeinfo
    real, dimension(sizeinfo) :: y

    g = sum(y)
  end function
end module
以下是主要程序:

program main
use foo

real, dimension(2) :: x = (/1.0, 2.0/)

call solve(x, g)

end program
结果是:

x=   1.000000       2.000000    
f(x)=   3.000000 

恐怕也没有编译,有一个类似的错误:
error:dummy procedure'f'中的接口不匹配(1):参数'y'中的形状不匹配
所有维度都应该是
,同样在
g(y)
函数中(否则你将混合显式和假定的形状数组),我想问题已经解决了!我希望通过在
g(y)
中明确显示数组的大小来获得安全性,但这可能不太可能。这与另一个答案有相同的问题。传递子例程的意义在于可以传递任何子例程。外部设备陈旧、过时且容易出错。对同一模块中的函数使用
external
来保存几行代码确实是一种糟糕的风格。更多信息,请参阅我之前的评论。但是,在这种情况下,您能举一个例子说明为什么外部容易出错,以及如果您有大量的子例程要调用该怎么办?你需要写很多的
接口吗?为什么?编写一个接口,这些子例程都符合该接口。这就是重点!您编写一个库,库的用户编写传递的子例程。因此,它们不能在一个模块中,因为其他人编写了它们(即使最后两个人碰巧都是您)。如果有一个或几个
callsub(sub,arg1,arg2)
,则您是对的。对不起,我不清楚,因为我真正想问的是如果有大量的
callsubs
调用其他
sub
s怎么办。此外,我仍然想知道为什么使用模块容易出错。我想知道是否有一个例子表明使用接口确实是一个好的实践。不,使用模块不容易出错,使用
external
是!!!正如我告诉过你的,你可以很容易地用
过程(sub)
替换
外部
。一旦你这样做了,你就会意识到
sub
作为一个接口,你可以在模块中有一个
abstract interface
,而不是
sub
,你就回到了以前的位置。