fortran77, iso_c_binding et c ssortingng

J’essaie d’appeler du code Fortran77 depuis C mais je n’ai pas trouvé le moyen approprié de passer un tableau de caractères C.

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 

Cette méthode fonctionne avec Fortran 90 et spécificateur de pointeur cible, mais Fortran 77 ne semble pas avoir de telles choses. Donc, le code ci-dessus ne comstack pas.

Le paramètre BIND(C) force la taille du paramètre c_message. Comment accéder aux autres éléments de la chaîne c_message?

Compilateur: GCC 4.8.2

J’essaie d’appeler du code Fortran77 depuis C mais je n’ai pas trouvé le moyen approprié de passer un tableau de caractères C.

Toutes les implémentations Fortran 77 que j’ai utilisées ont mis en place des mécanismes d’interopérabilité spécifiques avec C, qui impliquent généralement le côté C, qui connaît les conventions de gestion des noms et de passage d’arguments utilisées par le compilateur Fortran, et les utilise à l’interface. Les conventions du système GCC ne sont pas si difficiles à utiliser.

Vous semblez être intéressé par la fonctionnalité d’interopérabilité Fortran / C introduite dans Fortran en 2003, cependant. En supposant que votre code Fortran 77 soit également conforme à Fortran 2003 (ou que vous puissiez le faire), il devrait être possible d’écrire un wrapper interopérable dans Fortran 2003. Sachez toutefois que la fonctionnalité d’interopérabilité C ne fournit pas (directement) pour l’interopérabilité des variables Fortran ou des parameters de sous-programme de type character de longueur supérieure à 1 ou de nature différente de c_char . D’autre part, gardez également à l’esprit que la longueur d’un object de caractère Fortran n’est pas la même chose que la ou les dimensions d’un tableau de caractères.

Vous avez deux solutions interopérables pour fournir une interface face au C permettant d’accepter un tableau de caractères C. Le plus clair serait peut-être d’accepter un tableau de character taille supposée Fortran:

 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 

L’alternative la plus probable est d’accepter directement le pointeur de tableau de 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 

Ce dernier est nécessaire si le pointeur du tableau du côté C peut être nul. Les deux nécessitent également une longueur explicite si on ne peut pas compter sur le tableau pour qu’il soit terminé à zéro.

En tout état de cause, si vous voulez finalement une variable de character Fortran ayant une longueur supérieure à 1 (par opposition à un tableau de dimension supérieure à 1), les interfaces interopérables ne peuvent pas fournir cela directement – de tels types ne font pas partie de ceux auxquels les dispositions C interop sont applicables. Sauf si vous pouvez vous fier au type de caractère par défaut pour être c_char , vous devrez les c_char avec une copie en entrée (/ copie en sortie) afin de convertir les caractères entre les types. Avec l’ancienne interface, la manière de copier le tableau sur un character scalaire Fortran d’une longueur supérieure à 1 devrait être évidente. Pour la variante de pointeur, il peut être utile d’utiliser une fonction de conversion similaire à celle-ci:

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

(Dérivé de la sous-routine C_F_ssortingng_ptr sous-programme C_F_ssortingng_ptr du wiki Wiki)

D'un autre côté, si vous pouvez (ou de toute manière , compter sur c_char comme type de caractère par défaut), vous disposez d'une alternative supplémentaire. Vous pouvez utilement associer un tableau de caractères tel que le paramètre du premier exemple à un object caractère scalaire de type par défaut et dont la longueur est supérieure à un. En particulier, si un argument factice de la fonction enveloppée est un caractère scalaire de longueur supposée ou dont la longueur fixe ne dépasse pas le nombre d'éléments de tableau, vous pouvez vous fier à l'association d'arguments pour l'associer au tableau de caractères du wrapper. En d'autres termes, dans ce cas, vous pouvez simplement passer le tableau comme argument réel.

  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)); } 

Vous devez passer sgsortingng length en tant que paramètre caché. Voir mon article ici http://www.malcolmmclean.site11.com/www/MpiTutorial/CandFortran77.html