Estoy tratando de llamar a una función FORTRAN desde C
Mis preguntas son:
-
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");
-
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.
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
Por supuesto, todo esto depende de su compilador FORTRAN, pero en términos generales:
-
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.
-
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.
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