Вызов подпрограммы FORTRAN из C

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

Мои вопросы:

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

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

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

3 ответа

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

Строки - сложный случай, потому что технически в Си они являются массивами символов, и вы должны соответствовать этому в Фортране. Вы также должны иметь дело с различными определениями строк: 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

Конечно, все зависит от вашего компилятора 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
    

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

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

Другие вопросы по тегам