указатель как фиктивный аргумент - PullRequest
2 голосов
/ 15 октября 2010

Я несколько озадачен следующей программой

module test
   implicit none

   type TestType
      integer :: i
   end type

contains
   subroutine foo(test)
      type (TestType), intent(out) :: test
      test%i = 5 
   end subroutine

   subroutine bar(test)
      type (TestType), intent(out) :: test
      test%i = 6 
   end subroutine

end module

program hello
   use test
   type(TestType) :: t

   call foo(t)
   print *, t%i 
   call bar(t)
   print *, t%i 
end program hello

и его производные. Подробнее об этом позже. Как мы знаем, Fortran передает рутинные аргументы в виде передачи по ссылке, что означает, что сущность, появляющаяся в фиктивном аргументе test для foo и bar, является одним и тем же пространством памяти, предоставленным в стеке в program hello , Пока все хорошо.

Предположим, я определил в program hello type(TestType) :: t как указатель и выделил его.

program hello
   use test
   type(TestType), pointer :: t

   allocate(t)

   call foo(t)
   print *, t%i
   call bar(t)
   print *, t%i

   deallocate(t)
end program hello

Код работает, как и раньше, с той лишь разницей, что объект размещен не в стеке, а в куче.

Теперь предположим, что мы возвращаемся к выделенной стеку программе, и вместо этого строка подпрограммы определяется как

 subroutine bar(test)
    type (TestType), pointer :: test
    test%i = 6 
 end subroutine

Программа больше не компилируется, потому что вы должны использовать выделенную кучу версию, чтобы заставить ее работать, или, чтобы быть более точным, обязательно передать указатель на подпрограмму, когда подпрограмма определена, чтобы принять указатель как фиктивный аргумент. С другой стороны, если фиктивный аргумент не содержит ключевое слово pointer, подпрограмма будет принимать как указатели, так и не указатели.

Это заставляет меня задуматься ... какой смысл объявлять фиктивный аргумент указателем?

1 Ответ

4 голосов
/ 15 октября 2010

Переслано с comp.lang.fortran, ответ Тобиаса Бернса:

Теперь давайте вернемся к программе, выделенной из стека, и строка подпрограммы вместо этого определяется как

панель подпрограмм (тест) тип (TestType), указатель :: тест тест% i = 6 конец подпрограммы

Программа больше не компилируется, потому что вы должны использовать выделенная куча версия, чтобы она работала,

Это не совсем правильно: вы также не можете передать переменную ALLOCATABLE. манекену с атрибутом POINTER. Я думаю, что одна (практическая) причина что адрес указателя может сбежать, и вы, таким образом, вызовете псевдоним проблемы. Формальная причина в том, что ALLOCATABLE просто не УКАЗАТЕЛЬ; Кроме того, стандарт не говорит о куче против стека против статической памяти. И на самом деле, локальные массивы [с постоянными границами] будут часто создаются в статической памяти, а не в стеке (если вы не используете OpenMP или атрибут RECURSIVE). Таким образом, ваш «стек» пример может также может быть примером "статической памяти", в зависимости от компилятора и используемые опции.

или, если быть более точным, это обязательно передать указатель на подпрограмму, когда подпрограмма определена принять указатель в качестве фиктивного аргумента.

Это тоже не совсем верно. В Фортран 2008 вы можете пройти non-POINTER, который имеет атрибут TARGET, к фиктивному указателю, который имеет атрибут INTENT (IN). (Назначение указателя относительно указателя статус ассоциации; для манекенов без указателя намерения о значение хранится в переменной.)

Это заставляет меня задуматься ... какой смысл объявлять фиктивный аргумент указатель?

Хорошо, если аргумент имеет атрибут POINTER, вы можете выделить и освободить указатель цели, вы можете связать указатель с какой-то целью и т. д. До Фортрана 95 было невозможно иметь РАЗМЕЩЕННЫЙ манекен аргументы, таким образом, указатель должен быть использован, если (фиктивный) аргумент должен быть выделено в процедуре.

Если вы можете, вы должны попытаться использовать скорее ALLOCATABLEs, чем указатели - они проще в использовании, не пропускают память и не имеют позы проблемы alias-анализа для компилятора. С другой стороны, если вы хотите например, для создания связанного списка необходим указатель. (Хотя для кучи использование, также можно использовать выделяемые компоненты Fortran 2008. *)

*I mean:
   type t
       type(t), allocatable :: next
   end type

где компонент того же типа, что и определяемый тип; до F2008 это было разрешено только для указателей, но не для назначаемых.

и Р. Мэн

Как мы знаем, Фортран передает рутинные аргументы как пройти по ссылке,

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

В соответствии с последними стандартами, передача по ссылке в некоторых странах практически запрещена. случаев. Стандарт не использует эти слова в своем нормативном тексте, но Есть вещи, которые было бы непрактично пройти по ссылке.

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

Я думаю, что другие люди ответили на остальные посты адекватно. Немного также рассмотрел вышеупомянутый пункт, но я хотел подчеркнуть это.

Надеюсь, что это ответ на ваш вопрос.

...