Фортран в C интерфейс для массивов и скаляров - PullRequest
4 голосов
/ 09 января 2020

Я учусь взаимодействовать с Fortran с C. Я написал простой C код, который устанавливает все значения массива в 1:

#include <stdlib.h>
void cset( int *array, int size ) {
  for (size_t i = 0; i < size; i++) {
    array[i] = 1;
  }
  return;
}

Я хотел написать интерфейс Fortran для работы как с массивами (любого измерения), так и со скалярами.
Мой фортран код:

program main
  use iso_c_binding
  implicit none

  interface cset
    ! Interface for arrays.
    subroutine cset_array( array, size ) bind( C, NAME="cset" )
      import
      integer(C_INT), intent(inout)     :: array(*)
      integer(C_INT), value, intent(in) :: size
    end subroutine cset_array

    ! Interface for scalars. NOTE: Fortran values are passed by reference (so this should work)
    subroutine cset_scalar( scalar, size ) bind( C, NAME="cset" )
      import
      integer(C_INT), intent(inout)     :: scalar
      integer(C_INT), value, intent(in) :: size
    end subroutine cset_scalar

  end interface cset

  integer :: scalar = 0
  integer :: array(3) = 0
  integer :: array2d(3,3) = 0

  call cset( scalar, 1 )
  print *, scalar

  call cset( array, size(array) )
  print *, array

  ! Does not work???
  ! call cset( array2d, size(array2d) )

  ! But works for
  call cset_array( array2d, size(array2d) )
  ! OR call cset( array2d(1,1), size(array2d) )
  print *, array2d

end program main

Это хорошо работает для скаляров и 1D-массивов.

Почему интерфейс не работает для cset( array2d, size(array2d) ), но работает для cset_array( array2d, size(array2d) ) или call cset( array2d(1,1), size(array2d) )? В первом случае я получаю следующую ошибку (gfortran-7.4):

call cset( array2d, size(array2d) )
                                  1
Error: There is no specific subroutine for the generic ‘cset’ at (1)

Есть ли более «правильный» способ написания такого интерфейса? Можно ли передать скаляр таким образом?

Спасибо и всего наилучшего.

ОТНОСИТЕЛЬНО:
Передача двумерного массива из Фортрана в C
Передача скаляров и массивов (любых размеров) из Фортрана в C

1 Ответ

3 голосов
/ 09 января 2020

Нельзя использовать массивы предполагаемого размера (dimension(*)), чтобы разрешить использование одной и той же указанной процедуры c для массивов нескольких рангов (измерений). Из-за правил TKR (тип, вид, rank ) все указанные c процедуры предназначены только для одного ранга. Если вы попытаетесь передать другой массив рангов процедуре generi c, указанная процедура c не будет распознана, даже если есть возможность передать массив в процедуру c напрямую.

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

subroutine cset_array1( array, size ) bind( C, NAME="cset" )
  import
  integer(C_INT), intent(inout)     :: array(*)
  integer(C_INT), value, intent(in) :: size
end subroutine cset_array1

subroutine cset_array2( array, size ) bind( C, NAME="cset" )
  import
  integer(C_INT), intent(inout)     :: array(1,*)
  integer(C_INT), value, intent(in) :: size
end subroutine cset_array2

Если у вас есть только одна процедура, которая может принимать действительно все, например процедуры MPI, то можно используйте спецификатор компилятора c

!$GCC attributes no_arg_check

или то же самое с !$DEC

...