【问题标题】:error when calling a subroutine within subroutine在子程序中调用子程序时出错
【发布时间】:2017-09-28 06:41:50
【问题描述】:

您好,我已尝试在下面创建一个最小、完整且可验证的示例示例代码,以强调我收到的一条错误消息。错误是“(1) 处的参数 'func0' 中的类型不匹配;将 REAL(4) 传递给 COMPLEX(4)。

我在代码中指出了来自 (1) 的错误消息的位置。当我尝试在另一个子例程中调用一个子例程时会发生这种情况。

我最初尝试在 Sub2 中添加隐式 none,但随后我收到一条错误消息,提示 func0,func1 没有隐式类型。

我试着按照这篇文章的逻辑:How to call and use a subroutine inside another subroutine in fortran?

Module Sample

integer :: n,m

contains 

subroutine Sub1(func0,func1)

implicit none

   complex, dimension(-10:10, -10:10), intent(inout) :: func0,func1
   complex, dimension(-10:10, -10:10) :: Deriv0,Deriv1


     do while (100 > 0.000001) 

        Deriv0 = Deriv(func0)
        Deriv1 = Deriv(func1)

     end do

end subroutine Sub1

subroutine Sub2(func3)
!implicit none : if this line is not commented out, I still get error messages saying func0,func1 do not have implicit types

   real,dimension(0:20), intent(inout) :: Func3

   call Sub1(func0,func1) !error message from here, this is line (1)

end subroutine  Sub2

function Deriv(func)
implicit none

complex, dimension(-10:10, -10:10) :: func, Deriv

   do n=-9,9
   do m=-9,9

     Deriv(n,m) = func(n+1,m)-2*func(n,m)

   end do
   end do

end function Deriv

End Module Sample

如何解决此错误?谢谢。

【问题讨论】:

    标签: fortran subroutine


    【解决方案1】:

    这里有许多我们关注的概念:范围;协会;和继承。

    在问题的代码中有四个作用域单元:模块sample 和三个过程(两个子例程和一个函数)。这些都是不同的,但它们之间共享一些信息。

    首先查看implicit 语句。在模块中没有implicit,因此默认类型规则适用于模块的范围单元。 (尽管模块中没有任何内容是隐式类型的 - 模块变量和函数都是显式声明的。)sub1deriv 每个都有 implicit none,因此这里清楚地说明了类型规则(没有隐式类型)。

    sub2 中指定implicit none 时,编译器会抱怨func0func1 没有显式类型声明;如果没有implicit none,作用域单元sub2 会继承其宿主(模块)的类型规则,因此func0func1 是真实的。

    您可以在another question and its answers 中阅读有关范围单位和输入规则的信息。总之,把implicit none放在模块里。

    func0func1 的这种输入将我们引向范围界定的另一个方面。 sub1sub2 是完全不同的范围单位。这两个子例程可以共享有关声明的知识的唯一方法是通过一种形式的关联。

    这里有两种关联形式:宿主关联和参数关联。

    主机关联是每个子程序都可以访问变量nm。他们不引用这些变量,所以让我们忽略它们。主机关联还在sub2 中提供sub1 的显式接口,允许编译器抱怨类型不匹配。

    sub2 的作用域单元中,没有明确声明func0func1。这是implicit none 生效的错误;使用默认的隐式类型规则,它们是实标量变量或具有实标量结果的函数。如果你想让它们成为复杂的数组,你只需要这样声明它们。

    参数关联通过以下方式产生。我们将sub1 的虚拟参数与sub2 的实际参数相关联。这里的关键是关联:两个不同的事物碰巧指向同一个对象。这两个过程不共享任何未在每个过程中明确说明的内容。为了能够有一个与这些虚拟参数相关联的实际参数,sub2 的范围内必须存在适当的东西。目前没有。


    简而言之:您需要在sub2 中有一个合适的func0func1 声明。这些可能是局部变量或虚拟参数,具体取决于您希望程序如何运行。

    【讨论】:

    • 这对我很有帮助。按照您的建议,我可以通过在 sub2 中声明 func0,func1 来修复错误。我还在模块中添加了隐式无。也非常感谢所有其他的解释。如果我有任何问题,我会告诉你,但我现在还没有,这一切都非常清楚。谢谢!
    【解决方案2】:

    (免责声明:我实际上并不了解 Fortran。这个答案是 WAG。)

    在您的Sub2 子例程中,既没有声明func0 也没有声明func1,它们也不是参数。与代码的其他部分不同,Sub2 不包含implicit none 指令,因此编译器假定您打算将func0 用作REAL 变量,这会导致类型错误(因为Sub1 需要COMPLEX 变量)。

    我无法告诉您如何解决此问题,因为您的代码从不调用任何地方的 Sub2,但大概您必须从某个地方获取两个 COMPLEX 变量才能传递给 Sub1

    【讨论】:

    • 是的,我意识到没有隐式没有,当我添加它时,我只是收到有关 func0 的其他错误消息,func1 没有隐式类型。所以我想我会先从这个错误消息开始。 Func0, Func1 不应该在我的 Sub2 中定义,这正是我调用 Sub1 的原因,这是定义 func0, func1 的地方。我认为“包含”部分调用了我模块中的所有子例程和函数,我没有明确地“调用”每个函数/子例程。我在这里只使用了这个调用,因为 sub2 需要 sub1。谢谢你的回答,你可能是对的。但我不知道如何解决它
    • 例如:我的代码从不调用 sub1 或函数 Deriv,但是我没有从那里得到任何错误。我的模块有“包含”来处理这个问题(我认为?)一旦我添加了这个子例程 Sub2,当我尝试调用 Sub1 时就会出错。显然这个逻辑有问题,那么你建议如何调用 Sub2 呢?我从不调用 Sub1 或 Function Deriv,为什么我必须调用 Sub2?
    • @Integrals 你不必打电话给Sub2;它可能只是让我知道你打算如何使用它。现在我不知道这段代码应该实现什么,这就是为什么我不能告诉你该怎么做。
    • 感谢您的帮助。这只是一个示例代码,用于指示我收到的错误消息。它并不表明我想要达到的目标。让我试着解释清楚,对此感到抱歉。所以我的代码包含一个“包含”子程序 1、子程序 2 和一个函数的模块。子程序 1 使用来自我的函数的信息,但我没有明确地“调用”它。子程序 2 应该使用来自子程序 1 的信息,所以我为此使用了“调用”。整体代码使用 sub 1,2 和函数。就这样。这有帮助还是没有帮助?如果没有,你想知道什么?
    • 我应该使用隐含的 none 语句吗?如果是这样,那么我会收到不同的错误消息,即 func0、func1 没有隐式类型。我该如何解决?我不确定哪个错误实际上是我需要处理的错误;没有隐式类型或我上面帖子中的类型。再次感谢。很抱歉让我感到困惑。