Когда процедура (функция или подпрограмма), которую вы пытаетесь вызвать в своем коде, лежит на вне тела вашего program
, а также не является частью какого-либо module
, она называется внешняя функция (или подпрограмма).
Фортран - это язык статического типа, поэтому типы всех переменных и функций должны быть известны во время компиляции.Поэтому, если вы хотите сослаться на внешнюю функцию в вашей программе, у программы должен быть способ узнать ее тип возврата.У вас есть 3 ( плохие ) опции для этого, и я перечислю их, начиная с худшего:
- WORST : положитесь направило неявной типизации, которое совпадает с типом возвращаемого значения внешней функции с типом, связанным с ее идентификатором в вызывающей стороне (как вы это сделали в своем примере).
Почему вы не должныне так ли? Потому что это рак .Это делает смысл кода неясным, вы не можете знать, на что ссылается это имя.В некоторых случаях он может даже выглядеть как переменная массива, а не как функция.Кроме того, компилятор не проверяет соответствие аргументов в этом случае, поэтому, если у вас не включены конкретные параметры компилятора, код не будет работать в время выполнения или хуже, даст неправильные результаты.Более того, неявная типизация очень и очень редко используется в наши дни, в большинстве случаев это проблема.Всегда используйте implicit none
!
Как вы заметили, по умолчанию правила неявной типизации, любая переменная с именем, начинающимся с p
, будет иметь тип real
по умолчанию (в вашем компиляторе это real(4)
).Когда вы объявили результат функции как real*8
, который ваш компилятор интерпретировал как real(8)
(см. Последнее примечание), возникла ошибка.
BAD : Объявите имя и тип функции в области спецификации вызывающего абонента.
Вы сделали бы это так же, как объявили бы переменную, например:
program main
implicit none
real*8 :: x, y, power
Кстати, атрибут external
может быть применен к внешним процедурамкак твой.Более чем придание некоторым свойствам процедуры (может быть передано как фактический аргумент, устранение неоднозначности от внутренних процедур), это сделает яснее происхождение идентификатора.
program main
implicit none
real*8 :: x, y, power
external :: power
Почему бы вам не следуетсделать это? Компилятор также не проверяет аргументы.Это сильно ограничивает ваши возможности для связи с внешними функциями: аргументы не могут быть заданы в форме, предполагаемом ранге, полиморфными, параметризованными, грубыми или быть объявлены на стороне вызываемого как allocatable
, optional
, pointer
, target
, asynchronous
, volatile
или value
;возвращаемый тип не может быть массивом, или указателем, или размещаемым;функция не может быть передана в качестве аргумента, быть elemental
и, если pure
, не может использоваться в таких контекстах.И причиной всего этого является отсутствие явного интерфейса .
ПРИНЯТО : Укажите
interface
для вашей внешней функции в вызывающем абоненте.
Как это:
program main
implicit none
interface
real*8 function power(y)
real*8 :: y
end function
end interface
Таким образом, компиляторможет знать все детали декларации и все упомянутые ограничения не будут применяться.Полная свобода и ясность кода!
Почему вы не должны этого делать? Потому что есть лучший способ, который использует modules
!Ну, это вполне нормально делать в тех случаях, когда вы не можете использовать модули, например, при работе с уже существующим большим старым кодом.Недостатком является то, что у вас есть почти одинаковый код в двух разных местах, и они должны всегда совпадать.
Бонус: BETTER : использовать модули.
program main
use :: aux_module
implicit none
real*8 :: x, y
common /yvalue/ y
x = 3d0
y = 3d0
print *, power(x)
end
module aux_module
implicit none
contains
function power(x)
real*8 :: power
real*8 :: x, y
common /yvalue/ y
power = x ** y
end
end
Почему вы обязательно должны это делать? Поскольку с модулями интерфейсы доступны автоматически и неявно (меньше дублирования кода, никаких ограничений);модули можно перекомпилировать отдельно и обновлять, не нарушая код.Кроме того, вы можете объявлять общие переменные в области видимости модуля и избегать использования common
объявлений.Еще лучше версия вашего кода будет:
program main
use aux_module
implicit none
real*8 :: x
x = 3d0
y = 3d0
print *, power(x)
end
module aux_module
implicit none
real*8 :: y
contains
function power(x)
real*8 :: power
real*8 :: x
power = x ** y
end
end
Существует даже возможность включить ваши функции непосредственно в program
после contains
.Это рекомендуется, только если вы не планируете повторно использовать эту функцию в других программных модулях.@ 1096 * ответ IanBush охватывает этот случай.
Последнее замечание: посмотрите на этот ответ , чтобы понять, почему синтаксис real*8
нестандартен и его следует избегать.