Llamar a una subrutina FORTRAN desde C

4 minutos de lectura

avatar de usuario
kittu

Estoy tratando de llamar a una función FORTRAN desde C

Mis preguntas son:

  1. Si fortRoutine es el nombre de mi subrutina fortran, entonces estoy llamando a esto desde C como fortRoutine_. Si fortRoutine contiene solo un argumento de matriz de caracteres, entonces puedo pasar así:

    fortRoutine_("I am in fortran");
    
  2. Al llamar a las subrutinas FORTRAN, ¿cuándo debo usar pasar por valor y cuándo pasar por referencia?

Como soy nuevo en C, no tengo ni idea de esto. Si es posible, sugiera también algunos buenos enlaces de tutoriales.

  • proporcione más información como plataforma/compilador ya que lo que está preguntando depende en gran medida de la plataforma.

    – AndersK

    21 de noviembre de 2011 a las 6:23


avatar de usuario
MSB

La forma de hacer esto ahora es usar el enlace ISO C de Fortran en el lado de Fortran. Esto es parte del lenguaje estándar Fortran 2003 y está disponible en muchos compiladores; no es específico de gcc. Se ha descrito en muchas respuestas en este sitio. Como parte del estándar del lenguaje, es independiente del compilador y de la plataforma. Y no necesita conocer las convenciones internas de paso del compilador. El enlace ISO C, cuando se usa en la declaración de una subrutina o función de Fortran, hace que el compilador de Fortran use las convenciones de llamada de C para que ese procedimiento pueda llamarse directamente desde C. Nombre de la subrutina de Fortran, es decir, sin guiones bajos. El nombre utilizado por el enlazador proviene de la opción “enlazar”.

Las cadenas son un caso difícil porque técnicamente en C son matrices de caracteres y tienes que hacer coincidir esto en Fortran. También debe lidiar con las diferentes definiciones de cadenas: C tiene terminación nula, longitud fija de Fortran y relleno con espacios en blanco. El ejemplo muestra cómo funciona esto. Los números son más fáciles. El único problema con las matrices es que C es la fila principal y la columna Fortran principal, por lo que las matrices multidimensionales se transponen.

int main ( void ) {

   char test [10] = "abcd";

   myfortsub (test);

   return 0;

}

y

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

Compile el C en un archivo de objeto y use gfortran para compilar el fortran y vincular ambos:

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

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

La salida es:

 >abcd<           4

  • En general, esta es la forma de fallar, pero creo que muchas veces, si un programador de C pregunta, a menudo realmente no quiere profundizar en sus códigos FORTRAN 77 heredados y anteriores. Entonces, a veces es mejor escribir un contenedor en C.

    – Vladimir F Героям слава

    21 de noviembre de 2011 a las 9:33

  • O peor aún, no tienes el lujo de iso_c_binding. Aún así, +1 este es el enfoque a seguir si controlas ambos (aunque generalmente elijo administrar las cosas de la cadena en el lado C, en mi humilde opinión, mucho más simple).

    – usuario7116

    21 de noviembre de 2011 a las 12:59

avatar de usuario
usuario7116

Por supuesto, todo esto depende de su compilador FORTRAN, pero en términos generales:

  1. No, deberá pasar un argumento de longitud oculta para su cadena. Algunos compiladores los intercalan con los otros parámetros, directamente después de la cadena. Otros, agrupan todos los argumentos de longitud de cadena al final de la lista de argumentos.

    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.
    
  2. Casi siempre se pasa por referencia, pero puede alternar este comportamiento usando atributos en los argumentos ficticios en el lado de FORTRAN.

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

Aquí hay algunas referencias, que son aplicables en función de varios compiladores:

La respuesta depende del compilador y del sistema (técnicamente, su ABI). Para GCC (que es un compilador de C, C++, Ada y Fortran) lea el programación mixta fortran capítulo.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad