首页 > 解决方案 > fortran 函数是否总是将 retun 值的结果复制到接受变量中?

问题描述

mac osx catalina (latest)
gfortran 9.2
fortran standard "gnu"

通过类似下面的代码,我了解到,至少在这种情况下,在函数中构造get_numberresult值,然后将结果复制到接收变量。可能我也通过在该函数中以一个局部变量为目标的指针做了一个禁忌,但也许编译器对我很好,没有释放一个局部变量,所以我的指针仍然没问题。

我的问题是,这就是所有函数调用的行为方式,即在内存中构造值(无论是简单类型还是复杂类型),然后将值复制过来并丢弃原始结果?我的印象是接收函数调用值的变量只是被赋予了构造结果的内存。

假设我觉得大量的内存复制很浪费,或者假设像下面的代码那样它破坏了我的代码,并且我想在执行许多函数调用时避免它。是用子程序调用替换它们的解决方案吗?但我喜欢函数调用。如果内存复制是正常发生的,有没有办法在进行函数调用时避免内存复制?

module nums
  type number
     real :: n
  end type number

  type number_parent
     type(number), pointer :: p
   contains
     procedure, pass(this) :: get_number
  end type number_parent

contains

  function get_number(this) result(n)
    class(number_parent) :: this
    type(number), allocatable, target :: n
    allocate(n)
    n%n = 1.0
    this%p => n
  end function get_number

end module nums

program main
  use nums
  implicit none

  type(number) :: n
  type(number_parent) :: np

  n = np%get_number()

  print *, n%n
  print *, np%p%n

  n%n = n%n + 1.0

  print *, n%n
  print *, np%p%n

end program main

程序输出

> ./a.out 
   1.00000000    
   1.00000000    
   2.00000000    
   1.00000000 

标签: memoryfortrancopy

解决方案


我理解你的问题是关于一个叫做返回值优化的东西,你主要是在考虑简单的变量,非指针,不可分配。我的回答只会触及这些。我还将假设没有高级派生类型特性,如多态性和终结性。

我还将假设您仅在简单的分配中使用该功能。当然,函数通常可以出现在许多复杂的表达式中。

从函数返回简单变量时

   integer :: ext

   ext = func(1)

 contains

   integer function func(loc) result(res)
     res = loc + 1
   end function

  end

那么从概念上讲,局部变量用于返回值res,其值将在赋值后复制到外部变量。

在实践中,如果确实使用了一个单独的变量,它将被分配到堆栈上(这没有任何成本,不仅仅是几乎没有,真的没有)。堆可用于大型对象(主要是数组),编译器通常对此进行设置,但普通变量将在堆栈上。然后,当函数返回时,该值被复制到外部变量的位置ext并重置堆栈指针(这只是意味着其他函数或子例程稍后将使用该内存)。

复制确实会花费一些东西,它可能会或可能不会可以忽略不计。编译器通常能够对此进行优化并使函数ext直接使用外部变量作为其结果变量res,因此无需复制。但是,要查看它是否发生,您必须检查编译器生成的机器代码/程序集(或者,如果可用,任何中间表示)。它可能会根据优化级别 ( -O1, -O2, -O3) 和源代码中函数调用的确切上下文而有所不同。


推荐阅读