Как Владимир Ф. отвечает, в Fortran 2018 (и Fortran 2008+TS29113) можно использовать атрибут optional
для фиктивных аргументов в совместимой с C процедуре Fortran.
В Fortran 2008 это невозможно. Некоторые компиляторы до сих пор не поддерживают эту функцию. С этими компиляторами все еще (хотя и с дополнительной работой) можно поддерживать «необязательные» аргументы.
Процедура foo
вопроса не совместима с C под F2008 (даже с bind(C)
). Однако в F2008 можно подражать этой идее: иметь совместимую с C процедуру с type(c_ptr)
аргументами, которая обертывает желаемую процедуру Fortran. Эта интероперабельная оболочка может проверять наличие нулевых указателей (используя C_ASSOCIATED
), чтобы определить, присутствуют ли переданные далее аргументы или нет, и передавать разыменованные аргументы, если это так.
Например, сторона Fortran с оболочкой, совместимой с C, может выглядеть так:
module mod
use, intrinsic :: iso_c_binding
contains
subroutine foo_centry(a) bind(c,name='foo')
type(c_ptr), value :: a
real(c_float), pointer :: a_pass
nullify(a_pass)
if (c_associated(a)) call c_f_pointer(a, a_pass)
call foo(a_pass)
end subroutine foo_centry
subroutine foo(a)
real(c_float), optional :: a
end subroutine foo
end module mod
В Fortran 2018 у нас есть эта симметрия в интероперабельном интерфейсе: если процедура определена средствами, отличными от Fortran, но интероперабельный интерфейс имеет необязательный аргумент, то в F2018 мы получаем результат, что ссылка на эту процедуру с отсутствующим аргументом означает, что процедуре передается нулевой указатель.
В F2008 нам нужно обрабатывать и эту сторону: мы снова делаем это с неинтероперабельной процедурой F2008, которая обертывает интероперабельную процедуру с type(c_ptr)
аргументами: если аргумент присутствует, передать его адрес; если нет, пройдите C_NULL_PTR
.
Такой код F2008 может выглядеть как
module mod
use, intrinsic :: iso_c_binding
interface
subroutine foo_fentry(a) bind(c,name='foo')
import c_ptr
type(c_ptr), value :: a
end subroutine foo_fentry
end interface
contains
subroutine foo(a)
real(c_float), optional, target :: a
if (present(a)) then
call foo_fentry(c_loc(a))
else
call foo_fentry(c_null_ptr)
end if
end subroutine foo
end module mod
Помните об ограничениях, вызванных использованием c_loc
: в некоторых случаях может потребоваться использовать копию или принять другие защитные меры.
person
francescalus
schedule
30.07.2019