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

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

Мои вопросы:

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

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

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

Ответ 1

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

Строки сложны, потому что технически в 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 для компиляции fortran и ссылки:

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

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

Выход:

 >abcd<           4

Ответ 2

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

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

    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.
    
  • Почти всегда он проходит по ссылке, но вы можете переключать это поведение с помощью атрибутов фиктивных аргументов на стороне FORTRAN.

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

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

Ответ 3

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