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