Намерение Fortran (inout) против намерения пропуска

Хорошая практика диктует, что аргументы подпрограммы в Фортране должны иметь каждое заданное намерение (т.е. intent(in), intent(out) или же intent(inout) как описал этот вопрос)

subroutine bar (a, b)
    real, intent(in) :: a
    real, intent(inout) :: b
    b = b + a
    ...

Тем не менее, не указав намерение является допустимым Fortran:

subroutine bar (a, b)
    real, intent(in) :: a
    real :: b
    b = b + a
    ...

Существуют ли реальные различия помимо проверки времени компиляции для аргумента, указанного как intent(inout) а аргумент без указанного намерения? Есть ли что-то, о чем мне следует беспокоиться, если я переоснащаю свои намерения более старым, свободным от намерений кодом?

4 ответа

Решение

Согласно The Fortran 2003 Handbook от Adams и др., Существует одно различие между аргументом намерения (inout) и аргументом без заданного намерения. Фактический аргумент (т.е. в вызывающей стороне) в случае намерения (inout) всегда должен быть определим. Если намерение не указано, аргумент должен быть определим, если при выполнении подпрограммы делается попытка определить фиктивный аргумент. определимо означает установку значения: dummy_arg = 2.0. Ясно, что фактический аргумент должен быть переменной, если это сделано. Для намерения (inout) фактический аргумент должен быть определен независимо от того, делает ли это подпрограмма. Без указания намерений, это зависит от того, что происходит при этом конкретном вызове подпрограммы - если подпрограмма не определяет переменную, это нормально; если это так, то есть проблема - такие случаи, как запись в фактический аргумент, который является константой, очевидно, вызовут проблемы.

Это не означает, что компилятор будет диагностировать все эти случаи - то, что стандарт требует, чтобы компилятор диагностировал, является другой проблемой. Было бы почти невозможно обнаружить все ошибки требования к делу без указания намерения во время компиляции, поскольку нарушения зависят от потока выполнения кода. Компилятору намного проще диагностировать случай намерения (inout) и предупредить вас о проблемах с кодом.

Ваш вопрос побуждает меня задуматься (много чего нужно сделать прямо сейчас), можете ли вы столкнуться с различием в поведении, если ваш код передает ПАРАМЕТР в качестве фактического аргумента, который ваша подпрограмма затем пытается записать. Без объявления INTENT компилятор может это отпустить, что приведет к странному поведению. С объявлением я бы ожидал ошибку во время компиляции.

Мы с вами могли бы подумать, что нет разницы между INOUT и объявлением INTENT, но не забывайте, что существует множество старых программ на Фортране, и что совместимость со старыми языковыми версиями является важной особенностью новых стандартов. Если это был правильный (но изворотливый) FORTRAN77, то многие люди ожидают, что их код останется правильным (все еще хитрым) с компилятором Fortran 90+.

Беглое прочтение стандарта 2003 действительно указывает на то, что существует разница между INOUT и отсутствием INTENT, но требуется более тщательное чтение. Если вы проверите это, дайте нам знать ваши выводы; если у меня будет время, я сам это проверю и сообщу.

Чтобы понять роль намерения in/out, вам нужно знать, что внутри, Fortran эффективно передает переменные по ссылке. Это не всегда то же самое, что на самом деле передача по ссылке.

Если вы передаете внутренний подраздел двумерного массива подпрограмме, то есть: data(i1:i2, j1:j2)Затем Фортран копирует эти данные в непрерывный раздел памяти и передает новый адрес в подпрограмму. По возвращении данные копируются обратно в исходное местоположение.

Указав INTENTКомпилятор может пропустить одну из операций копирования.

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

Чтобы как-то расширить ответ MSB, исключение дает вам большую гибкость за счет меньшего количества проверок во время компиляции. Без, вы можете передать буквальную константу, если знаете, что ветвь кода не будет пытаться ее изменить, с intent(inout)компилятор, вероятно, лает на вас, если вы попробуете это сделать. Это может быть полезно с «двойными» процедурами, которые изменяют или не изменяют какой-либо аргумент в зависимости от параметров, например:

      subroutine copy(x,a,readwrite)
integer :: x, a
integer, intent(in) :: readwrite

if (readwrite == 0) then
  x = a
else
  a = x
end if

end subroutine

Если вы хотите добавить intent к x а также a, Это должно быть inoutдля обоих, потому что оба потенциально читаются и изменяются. Но это не позволит вам написать, например,

      call copy(x,3,0)  ! equiv. to x=3
call copy(42,a,1) ! equiv. to a=42

Этот пример довольно глупый, но подумайте о более сложной подпрограмме, которая может читать или записывать в файл с некоторым сложным форматированием. (Я не говорю, что это лучшее решение, но это то, что вы легко найдете.)

Другие вопросы по тегам