всегда ли функции fortran копируют результаты значения retun в принимающую переменную? - PullRequest
1 голос
/ 05 августа 2020
mac osx catalina (latest)
gfortran 9.2
fortran standard "gnu"

С помощью чего-то вроде приведенного ниже кода я понял, что, по крайней мере, в этом случае, внутри функции get_number создается значение result, а затем результаты копируются в принимающую переменную. . Вероятно, я также сделал нет-нет, указав указатель на локальную переменную внутри этой функции, но, возможно, компилятор был мил со мной, не освобождая локальную переменную, поэтому мой указатель все еще был в порядке.

Мой вопрос: так ли ведут себя все вызовы функций, а именно, что значение, будь то простой тип или сложный тип, создается в памяти, а затем значения копируются, а исходный результат отбрасывается? У меня создалось впечатление, что переменной, получающей значение вызова функции, просто была предоставлена ​​память сконструированного результата. это нарушает мой код, и я хотел избежать этого при выполнении множества вызовов функций. Есть ли решение заменить их вызовами подпрограмм? Но мне нравятся вызовы функций. Если копирование памяти происходит обычно, есть ли способ избежать копирования памяти при вызове функций?

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 

1 Ответ

3 голосов
/ 06 августа 2020

Я понял, что ваш вопрос касается вещи, называемой оптимизацией возвращаемого значения , и вы в основном думали о простых переменных, без указателя, без распределения. Мой ответ коснется только этого. Я также не буду предполагать никаких дополнительных функций производных типов, таких как полиморфизм и финализация.

Я также предполагаю, что вы используете эту функцию только в простом назначении. Конечно, в общем, функции могут появляться во многих сложных выражениях.

Когда вы возвращаете простую переменную из функции

   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) и от точного контекста вызова функции в исходном коде.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...