Я пытаюсь вызвать некоторый код Fortran77 из C, но я не нашел правильного способа передачи массива символов C.
Все реализации Fortran 77, которые я когда-либо использовал, предоставляли специфичные для реализации механизмы взаимодействия с C. Как правило, они предполагают, что сторона C знает соглашения об изменении имен и передаче аргументов, используемые компилятором Fortran, и использует их в интерфейсе. Соглашения системы GCC не так уж сложны в использовании.
Однако вас, похоже, интересует средство взаимодействия Fortran/C, представленное в Fortran 2003. Предположим, что ваш код на Fortran 77 также совместим с Fortran 2003 (или его можно заставить сделать так), должна быть возможность написать интероперабельную оболочку на Fortran 2003. Однако имейте в виду, что средства взаимодействия C не обеспечивают (напрямую) для взаимодействия переменных Фортрана или параметров подпрограммы типа character
с длиной больше 1 или видом, отличным от c_char
. С другой стороны, имейте в виду, что длина символьного объекта Fortran — это не то же самое, что размер(а) массива символов.
У вас есть несколько интероперабельных альтернатив для предоставления C-обращенного интерфейса, с помощью которого можно принимать массив C char
. Возможно, самым ясным было бы принять массив Fortran предполагаемого размера 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 может быть нулевым. Оба требуют явной передачи длины, если нельзя полагаться на то, что массив завершается нулем.
В любом случае, если вы в конечном итоге хотите, чтобы переменная Fortran 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_F_string_ptr
C_interface_module из Fortran Wiki)
С другой стороны, если вы можете (или в любом случае делаете) полагаться на тип символа по умолчанию, равный c_char
, то у вас есть дополнительная альтернатива. Вы можете с пользой связать массив символов, такой как параметр в первом примере, со скалярным символьным объектом типа по умолчанию и длиной больше единицы. В частности, если фиктивный аргумент обернутой функции представляет собой скалярный символ с предполагаемой длиной или с фиксированной длиной, не превышающей количество элементов массива, то вы можете полагаться на ассоциацию аргумента, чтобы связать его с массивом символов в оболочке. Другими словами, в этом случае вы можете просто передать массив в качестве фактического аргумента.
person
John Bollinger
schedule
20.12.2016
bind(C)
— это Fortran 2003. - person Vladimir F   schedule 20.12.2016CHARACTER*(C_CHAR)
синтаксически неверно. Вы должны просто использоватьCHARACTER(kind=C_CHAR)
и не заботиться о том, является ли ваш код F77 или F чем-то еще. Большинство кодов Fortran 77 являются допустимыми кодами Fortran 2008. - person Vladimir F   schedule 20.12.2016CHARACTER*(C_CHAR)
правильно. Это просто не означает, что вы (спрашивающий) думаете: это символ длиныc_char
, а не типаc_char
. Еслиc_char
не является1
, который не является (F2008) C-совместимым. - person francescalus   schedule 20.12.2016