Передача массива Fortran int в C ++ путем вызова функции C ++ в Fortran - PullRequest
4 голосов
/ 13 мая 2010

Я пытаюсь вызвать функцию C ++ в подпрограмме Fortran. Эта функция C ++ предназначена для обновления целочисленного массива. Вот нерабочий код, который я написал. В чем проблема?

! Fortran function that calls a C++ function.

subroutine my_function()

      integer(4) ar(*)

      integer(4) get_filled_ar

      ! Need correct syntax here.
      ar = get_filled_ar()
end


// C++ function:

    extern "C" {
        void get_filled_ar(int *ar){
            ar[0] = 1;
            ar[1] = 10;
            ar[3] = 100;
        }
    }

Ответы [ 2 ]

7 голосов
/ 13 мая 2010

В Fortran 2003 существует стандартный и, следовательно, независимый от платформы и компилятора способ вызова C из Fortran, а также любой язык, использующий интерфейс вызова C. Также вызывать Fortran из C. Хотя различные авторы компиляторов постепенно добавляют функции Fortran 2003, а завершенных компиляторов 2003 мало, связывание ISO C уже некоторое время доступно во многих компиляторах. Привязка ISO C работает лучше, чем предыдущие специальные методы, которые иногда плохо документированы и варьируются между компиляторами и платформами. Чтобы вызвать C из Fortran, вы пишете «интерфейс», который сообщает компилятору Fortran, что он должен использовать соглашения о вызовах C и типы C.

Вот пример. Как писал Майк, поскольку функция C ++ возвращает void, обрабатывайте ее в Фортране как подпрограмму и вызывайте ее. Таким образом, ему не нужно указывать тип. Кроме того, где-то в Fortran вы должны зарезервировать хранилище для массива - самый простой способ - с объявлением с числовым значением для измерения. И вам нужна основная программа на каком-то языке.

program test_call_C

use iso_c_binding

implicit none

interface c_interface

   subroutine get_filled_ar (ar) bind (C, name = "get_filled_ar")

   use iso_c_binding

   implicit none

   integer (c_int), intent (out), dimension (*) :: ar

   end subroutine get_filled_ar

end interface c_interface


integer (c_int), dimension (0:3) :: ar

call get_filled_ar (ar)

write (*, *) "Fortran: ar:", ar

stop

end program test_call_C

и в С:

void get_filled_ar (
   int ar []
) {

   ar [0] = 1;
   ar [1] = 10;
   ar [2] = 100;

   return;

}

Примеры команд:

gcc -c get_filled_ar.c
gfortran get_filled_ar.o test_call_C.f90  -o test_call_C.exe
./test_call_C.exe

Для вызова вашего кода C ++ используйте следующие команды. Имя, указанное в «bind», устраняет необходимость в конце подчеркивания, поэтому ваш код C ++ работает напрямую.

g++ -c cplusplus.cc
gfortran cplusplus.o test_call_C.f90  -o test_call_Cplusplus.exe
./test_call_Cplusplus.exe
2 голосов
/ 13 мая 2010

Вот полная программа с вашим кодом, которая должна работать (по крайней мере, в Linux с gcc / gfortran).

В файле фортрана fortran.f введите:

     IMPLICIT NONE      
     CALL my_function()
     END

! FORTRAN function that calls a C++ function

     subroutine my_function()
! Tell fortran about the C++ function:
       external get_filled_ar

       integer ar(4)

! As the C++ function returns void, call it as a subroutine in
! fortran:
       call get_filled_ar(ar)
! To check it worked, print out the numbers:
       do i = 1,4
          write(*,*) i,"->",ar(i)
       enddo
     end

В cplusplus.cc положить:

extern "C"
{
  void get_filled_ar_(int* ar) // note extra underscore to keep linker happy
  {
    ar[0] = 1;   
    ar[1] = 10;
    ar[3] = 100;
  }    
}

Затем сборка (в linux с gcc / gfortran, может отличаться в других системах) с:

gfortran -c fortran.f
gcc -c cplusplus.cc
gfortran -o program-name fortran.o cplusplus.o
...