Intereting Posts

Интерфейсы совместимости Fortran-C и плавающие массивы

У меня есть большой существующий код Fortran95. Оно использует

real(dp), dimension(num) :: array 

объявлять массивы.

Я хочу присоединиться к некоторому C-коду и обнаружил, что могу это сделать, написав интерфейсы с C-функциями и объявив массивы как

 use iso_c_binding real(c_double), allocatable, target :: array(:) 

У меня есть функции fortran, которые называют C-функциями как

 call myfunction(c_loc(array)); 

Что необходимо для передачи real(dp) массива в myfunction? По-видимому, мне нужно будет сделать C-указатель (как?). Есть ли другой способ, чем копирование массива? Можно ли гарантировать, что оба типа действительно относятся к совместимым блокам данных с двойной точностью? Самое главное, что решение должно работать с компиляторами GNU. Обратите внимание, что замена real(dp) real(c_double) везде в существующем коде Fortran для меня сейчас не является вариантом.

Если нет альтернативы копированию всего массива, как бы я сделал это правильно в интерфейсе?

Во-первых, я предполагаю, что вы определяете dp как параметр в модуле где-то. Вы можете просто использовать

 integer, parameter :: dp = c_double 

в этом модуле (и if (dp /= c_double) stop "Bletchful sytem" где-то.

Передача массива между C и Fortran работает следующим образом:

 module foo use iso_c_binding private public :: bar interface subroutine bar(a,n) bind(C) import real(kind=c_double), dimension(*), intent(inout) :: a integer(c_size_t), value, intent(in) :: n end subroutine bar end interface end module foo 

Ваша функция C тогда будет

 void bar(double *a, size_t n) 

Редактировать:

Способ вызова вашей функции C из Fortran был бы тогда

 program main use iso_c_binding use foo real(c_double), dimension(10) :: a call bar(a,size(a,kind=c_size_t)) print *,a end program main 

Изменить 2:

Если вы действительно хотите копировать / копировать каждый раз, вы можете сделать что-то вроде

  subroutine bar2(array) real(kind=c_double), intent(inout), dimension(:) :: array real(kind=c_double), dimension(size(array)) :: a a = array ! Copy in call bar(a,size(a,kind=c_size_t)) array = a ! Copy out end subroutine bar2 end module foo 

Но я не понимаю, зачем это нужно.

Редактировать 3:

Если вы боитесь несоответствия между типами данных C и Fortran, вы можете написать общую оболочку, чтобы обойти это. Вот как это могло бы выглядеть:

 module foo use iso_c_binding implicit none private public :: bar interface subroutine bar_double(a,n) bind(C) import real(kind=c_double), dimension(*), intent(inout) :: a integer(c_size_t), value, intent(in) :: n end subroutine bar_double end interface interface subroutine bar_float(a,n) bind(C) import real(kind=c_float), dimension(*), intent(inout) :: a integer(c_size_t), value, intent(in) :: n end subroutine bar_float end interface interface bar module procedure bar_aux_double, bar_aux_float end interface bar contains subroutine bar_aux_double (a) real(kind=c_double), dimension(:), intent(inout) :: a call bar_double (a, size(a,kind=c_size_t)) end subroutine bar_aux_double subroutine bar_aux_float (a) real(kind=c_float), dimension(:), intent(inout) :: a call bar_float (a, size(a,kind=c_size_t)) end subroutine bar_aux_float end module foo 

Тогда ваша основная программа могла бы выглядеть

 program main use foo integer, parameter :: dp = selected_real_kind(15) integer, parameter :: sp = selected_real_kind(6) real(dp), dimension(10) :: a_dp real(sp), dimension(10) :: a_sp call bar(a_dp) call bar(a_sp) print *,a_dp,a_sp end program main 

где вы вообще не ссылаетесь на iso_c_binding. Если для dp или sp нет функции-обертки, компиляция завершится неудачей из-за отсутствия общей процедуры.

Если вы используете модули, не беспокойтесь слишком много, смешивая dp и c_double внутри Fortran. В очень маловероятном случае, когда selected_real_kind(15, 307) /= c_double компилятор будет жаловаться при проверке интерфейсов процедуры. В противном случае он увидит, что номера номеров согласуются, и все равно, как вы называете константу вида (кроме случаев, когда объявляются совместимые процедуры).