fortran77, iso_c_binding и строка c

Я пытаюсь вызвать некоторый код Fortran77 из C, но я не нашел правильного способа передачи массива C char.

   SUBROUTINE My_F_Code (c_message)  BIND(C, NAME='my_f_code')
     USE ISO_C_BINDING
     IMPLICIT NONE
     CHARACTER*(C_CHAR)      c_message
     CHARACTER*(256)         f_message
     CALL C_F_POINTER( C_LOC(c_message), f_message)
     WRITE(*,*) f_message,LEN(f_message)
   END

Этот метод работает с Fortran 90 и target, указателем указателя, но Fortran 77, похоже, не имеет таких вещей. Итак, приведенный выше код не компилируется.

BIND(C) установить для параметра c_message значение 1. Как получить доступ к другим элементам строки c_message?

Компилятор: GCC 4.8.2

2 ответа

Решение

Я пытаюсь вызвать некоторый код Fortran77 из C, но я не нашел правильного способа передачи массива C char.

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

Однако вас, похоже, интересует средство взаимодействия Fortran/C, появившееся в Fortran 2003. Предполагая, что ваш код Fortran 77 также соответствует Fortran 2003 (или может быть сделан для этого), в Fortran 2003 должна быть возможность написать совместимую оболочку. Однако следует помнить, что средство взаимодействия с C не предоставляет (напрямую) для взаимодействия переменных Фортрана или параметров подпрограммы типа character с длиной больше 1 или видом, отличным от c_char, С другой стороны, имейте в виду, что длина символьного объекта на Фортране - это не то же самое, что размерность (и) массива символов.

У вас есть несколько совместимых альтернатив для обеспечения интерфейса C, с помощью которого можно принять C char массив. Возможно, самым ясным было бы принять предполагаемый размер Фортрана character массив:

SUBROUTINE My_F_Code (c_message)  BIND(C, NAME='my_f_code')
    USE ISO_C_BINDING
    IMPLICIT NONE
    CHARACTER(kind=C_CHAR), dimension(*), intent(in) :: c_message
    ! ...
END

Наиболее вероятной альтернативой является непосредственное принятие указателя массива C:

SUBROUTINE My_F_Code (c_message)  BIND(C, NAME='my_f_code')
    USE ISO_C_BINDING
    IMPLICIT NONE
    type(C_PTR), value :: c_message
    ! ...
END

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

В любом случае, если вы в конечном итоге хотите Фортран character Если переменная имеет длину больше 1 (в отличие от массива, имеющего размерность больше 1), то взаимодействующие интерфейсы не могут обеспечить это напрямую - такие типы не входят в число тех, к которым применимы положения о взаимодействии C. Если вы не можете полагаться на вид символов по умолчанию, чтобы быть c_char вам нужно соединить их с копированием (/ копированием), чтобы преобразовать символы между видами. С прежним интерфейсом должно быть очевидно, как вы можете скопировать массив в скаляр Фортрана character имеющий длину больше 1. Для варианта указателя может быть полезно использовать функцию преобразования что-то вроде этого:

subroutine C_string_ptr_to_F_string(C_string, F_string)
    use ISO_C_BINDING
    type(C_PTR), intent(in) :: C_string
    character(len=*), intent(out) :: F_string
    character(len=1, kind=C_CHAR), dimension(:), pointer :: p_chars
    integer :: i
    if (.not. C_associated(C_string)) then
      F_string = ' '
    else
      call C_F_pointer(C_string, p_chars, [huge(0)])
      do i = 1, len(F_string)
        if (p_chars(i) == C_NULL_CHAR) exit
        F_string(i:i) = p_chars(i)
      end do
      if (i <= len(F_string)) F_string(i:) = ' '
    end if
end subroutine

( Получено из C_interface_module от Fortran Wiki C_F_string_ptr подпрограмма)

С другой стороны, если вы можете (или в любом случае делаете) полагаться на вид символов по умолчанию, чтобы c_char тогда у вас есть дополнительная альтернатива. Вы можете с пользой сделать так, чтобы массив символов, такой как параметр в первом примере, был связан со скалярным символьным объектом по умолчанию с типом и длиной больше единицы. В частности, если фиктивный аргумент обернутой функции является скалярным символом с предполагаемой длиной или с фиксированной длиной, не превышающей количество элементов массива, то вы можете положиться на ассоциацию аргумента, чтобы связать его с массивом символов в оболочке. Другими словами, в этом случае вы можете просто передать массив в качестве фактического аргумента.

  SUBROUTINE FCODE(STR, N)
  CHARACTER*(*) STR
  INTEGER N
  WRITE(*,*), STR, N
  END


  void foo(char *str)
  {
      int N = 10;
      printf("Calling fortran\n");
      fcode_(str,  &N, strlen(str)); 
  }

Вам нужно передать длину sgtring как скрытый параметр. Смотрите мою статью здесь http://www.malcolmmclean.site11.com/www/MpiTutorial/CandFortran77.html

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