Вызов подпрограммы FORTRAN из C - PullRequest
13 голосов
/ 21 ноября 2011

Я пытаюсь вызвать функцию FORTRAN из C

Мои вопросы:

  1. Если fortRoutine - это имя моей подпрограммы на фортране, то яназывая это из C как fortRoutine_.Если fortRoutine содержит только один аргумент массива символов, тогда я могу передать его следующим образом:

    fortRoutine_("I am in fortran");
    
  2. При вызове подпрограмм FORTRAN, когда я должен использовать передачу по значению и когда передача по ссылке?

Поскольку я новичок в C, я понятия не имею об этом.Если возможно, пожалуйста, предложите несколько хороших обучающих ссылок.

Ответы [ 3 ]

23 голосов
/ 21 ноября 2011

Способ сделать это сейчас - использовать привязку Fortran ISO C на стороне Fortran.Это является частью стандарта языка Fortran 2003 и доступно во многих компиляторах;это не специфично для gcc.Это было описано во многих ответах на этом сайте.Как часть языкового стандарта, он не зависит от компилятора и платформы.И вам не нужно знать о внутренних условных обозначениях компилятора.Привязка ISO C, когда она используется в объявлении подпрограммы или функции Fortran, заставляет компилятор Fortran использовать соглашения о вызовах C, чтобы эту процедуру можно было напрямую вызывать из C. Вам не нужно добавлять скрытые аргументы или имяНазвание фортрановой подпрограммы, т.е. без подчеркивания.Имя, используемое компоновщиком, происходит из опции «bind».

Строки - сложный случай, потому что технически в C они являются массивами символов, и вы должны соответствовать этому в Fortran.Вы также должны иметь дело с различными определениями строк: C завершен нулем, Fortran фиксированной длины и дополнен пробелами.Пример показывает, как это работает.Числа проще.Единственная проблема, связанная с массивами, заключается в том, что C является главным и основным столбцом Fortran, поэтому многомерные массивы транспонируются.

int main ( void ) {

   char test [10] = "abcd";

   myfortsub (test);

   return 0;

}

и

subroutine myfortsub ( input_string ) bind ( C, name="myfortsub" )

   use iso_c_binding, only: C_CHAR, c_null_char
   implicit none

   character (kind=c_char, len=1), dimension (10), intent (in) :: input_string
   character (len=10) :: regular_string
   integer :: i

   regular_string = " "
   loop_string: do i=1, 10
      if ( input_string (i) == c_null_char ) then
         exit loop_string
      else
         regular_string (i:i) = input_string (i)
      end if
   end do loop_string

   write (*, *) ">", trim (regular_string), "<", len_trim (regular_string)

   return

end subroutine myfortsub

Вы компилируете C вобъектный файл и используйте gfortran для компиляции фортрана и связывания обоих:

gcc-mp-4.6   \
         -c  \
         test_fortsub.c

gfortran-mp-4.6   \
     test_fortsub.o  \
     myfortsub.f90  \
     -o test_fortsub.exe

Вывод:

 >abcd<           4
3 голосов
/ 21 ноября 2011

Конечно, все зависит от вашего компилятора FORTRAN, но в целом:

  1. Нет, вам необходимо передать аргумент скрытой длины для вашей строки.Некоторые компиляторы чередуют их с другими параметрами непосредственно после строки.Другие группируют все аргументы длины строки в конце списка аргументов.

    char str[11] = {0};
    fortranFunc_(str, sizeof(str) - 1);
    // remember that 'str' will need to be null terminated
    // and will be padding with spaces to fit the length
    // so for C passing strings to Fortran specify the length
    // less 1 so you can add a nul terminator, and on all strings
    // being filled in by FORTRAN, trim-end all spaces.
    
  2. Почти всегда это передается по ссылке, но вы можете переключать это поведение, используя атрибуты на фиктивных аргументахна стороне FORTRAN.

    int value = 10;
    fortranFunc_(&value);
    // INTEGER I
    

Вот некоторые ссылки, которые применимы на основе различных компиляторов:

2 голосов
/ 21 ноября 2011

Ответ зависит от компилятора и системы (технически, ее ABI). Для GCC (который является компилятором C, C ++, Ada и Fortran) прочитайте главу fortran смешанное программирование .

...