Можно ли вызвать скалярную функцию C из Фортрана с аргументами массива?

Недавно я столкнулся с ситуацией, когда я хотел вызвать функцию C из Фортрана из-за полезного фрагмента кода C. Для удобства операций с массивами я хотел иметь возможность вызывать эту функцию также с аргументами массива, но она принимала только скалярные аргументы.

В Фортране, конечно, можно просто объявить процедуру elemental, чтобы достичь этого, и можно объявить интерфейс к процедуре C с помощью bind(C). Однако, поскольку C не имеет концепции элементарных процедур, стандарт Fortran (2008) исключает эту комбинацию:

C1246 Элементарная процедура не должна иметь атрибута BIND.

Итак, можно ли реализовать эту функциональность в Фортране?


person sigma    schedule 07.12.2012    source источник


Ответы (1)


После некоторого поиска я обнаружил, что это возможно и довольно просто, используя Fortran 2003 и внутренний модуль iso_c_binding; Я подумал, что мне следует задокументировать это здесь. Интерфейс с атрибутом bind может быть pure, поэтому на него можно ссылаться в процедуре Fortran, которая сама по себе elemental.

Ниже приводится краткий пример макроса C99 isnan, который возвращает ненулевое целочисленное значение, если его аргумент - NaN. Конечно, это также можно сделать для любой пользовательской функции C / C ++, не имеющей побочных эффектов.

elemental function isnan(val)
  use, intrinsic :: iso_c_binding
  implicit none

  real(c_double), intent(in) :: val
  logical(c_bool) :: isnan

  interface
    pure function isnan_C(val) bind(C, name = 'isnan')
      import
      ! Pass the parameter by value:
      real(c_double), value, intent(in) :: val
      integer(c_int) :: isnan_C
    end function
  end interface

  isnan = isnan_C(val) /= 0_c_int
end function

Пример вывода с использованием массива с некоторыми значениями NaN:

program main
  use, intrinsic :: iso_c_binding
  implicit none

  real(c_double) :: nan(2,2) = 0.
  nan(:,2) = nan(1,1)/0.

  write(*,'(4F6.2 / 4L6)') nan, isnan(nan) ! Output: 0.00 0.00  NaN  NaN
                                           !            F    F    T    T
end program
person sigma    schedule 07.12.2012
comment
Иногда бывает трудно уловить, если функция C чистая, а может и не быть. Тогда может пригодиться IMPURE ELEMENTAL. - person Vladimir F; 08.12.2012
comment
+1 за предложение impure. Не похоже, что в настоящее время эта функция имеет широкую поддержку компилятора, но, по крайней мере, gfortran (4.7) реализовал ее. - person sigma; 10.12.2012