function - subprogramas - raiz cuadrada en fortran
Uso correcto de módulos, subrutinas y funciones en Fortran (3)
Los módulos son siempre lo correcto para usar ;-)
Si tiene un programa F90 muy simple, puede incluir funciones y subrutinas en el bloque ''contains'':
program simple
implicit none
integer :: x, y
x = ...
y = myfunc(x)
contains
function myfunc(x) result(y)
implicit none
integer, intent(in) :: x
integer :: y
...
end function myfunc
end program
Entonces, la interfaz de las funciones / subrutinas se conocerá en el programa y no será necesario definirla en un bloque de interfaz.
Para programas más complejos, debe mantener todas las funciones / subrutinas en módulos y cargarlas cuando sea necesario. Por lo tanto, no necesita definir interfaces, ya sea:
module mymod
implicit none
private
public :: myfunc
contains
function myfunc(x) result(y)
implicit none
integer, intent(in) :: x
integer :: y
...
end function myfunc
end module mymod
program advanced
use mymod, only: myfunc
implicit none
integer :: x, y
x = ...
y = myfunc(x)
end program advanced
El módulo y el programa pueden (en realidad deberían) estar en archivos separados, pero el módulo debe compilarse antes del programa real.
Recientemente aprendí sobre los bloques de interfaz cuando agrego una función a mi programa Fortran. Todo funciona bien y ordenadamente, pero ahora quiero agregar una segunda función en el bloque de interfaz.
Aquí está mi bloque de interfaz:
interface
function correctNeighLabel (A,i,j,k)
integer :: correctNeighLabel
integer, intent(in) :: i,j,k
integer,dimension(:,:,:),intent(inout) :: A
end function
function correctNeighArray (B,d,e,f)
character :: correctNeighArray
integer, intent(in) :: d,e,f
character, dimension(:,:,:),intent(inout) :: B
end function
end interface
Me parece que esta puede no ser la mejor opción.
He investigado las subrutinas, pero no estoy muy seguro de que sea la solución correcta. Lo que estoy haciendo es relativamente simple, y necesito pasar argumentos a la subrutina, pero todas las subrutinas que he visto son a) complicadas (es decir, demasiado complicadas para una función), yb) no toman argumentos, se comportan como si manipularan variables sin que se les pasaran a ellas.
Realmente no he investigado los módulos correctamente, pero por lo que he visto, no es lo correcto.
¿Qué debería usar cuándo y cómo lo hago mejor?
Secundar y extender lo que ya se ha dicho. Es mejor poner sus procedimientos (subrutinas y funciones) en módulos y "usarlos" porque les permite verificar la consistencia automática de las interfaces con poco esfuerzo. Las otras formas tienen inconvenientes. Si define la interfaz con un bloque de interfaz, tiene tres cosas que mantener en lugar de dos: la interfaz, el procedimiento en sí y la llamada. Si haces un cambio, entonces los tres tienen que ser modificados para ser consistentes. Si usa un módulo, solo dos deben ser cambiados. Una razón para usar un bloque de interfaz es si no tiene acceso al código fuente (por ejemplo, una biblioteca precompilada) o si el código fuente está en otro idioma (por ejemplo, está usando el código C a través de la vinculación ISO C).
El inconveniente del enfoque "contiene" es que los procedimientos contenidos heredan todas las variables locales del programa principal ... que no es muy modular y puede ser muy confuso si olvida esta "característica".
las respuestas de alexurba y MSB son correctas y útiles como de costumbre; permítanme dar más detalles sobre un punto: si los módulos son el camino a seguir (y lo son), ¿para qué sirven las interfaces?
Para funciones y subrutinas en módulos, cualquier cosa que use
s ese módulo puede ver automáticamente esas interfaces; las interfaces se generan cuando se compila el módulo (esa información, entre otras cosas, va al archivo .mod que se genera al compilar un módulo). Entonces no necesitas escribirlo tú mismo. Del mismo modo, cuando utilizas un subprograma CONTAIN
ed (que, de acuerdo con MSB, me resulta más confuso y útil, se los considera mejor como closures o subrutinas anidadas que las subrutinas externas), el programa principal ya puede ''ver'' la interfaz explícitamente y no necesita que lo escriba para eso.
Los bloques de interfaz son para cuando no puede hacer esto, cuando el compilador no puede generar la interfaz explícita para usted o cuando desea algo diferente de lo que se le da. Un ejemplo es cuando se usa la interoperabilidad de C-Fortran en Fortran 2003. En ese caso, el código de Fortran se enlaza con alguna biblioteca de C (por ejemplo) y no tiene forma de generar una interfaz fortran correcta para la rutina C para usted. hágalo usted mismo, escribiendo su propio bloque de interfaz.
Otro ejemplo es cuando ya conoce las interfaces para las subrutinas, pero cuando quiere crear una nueva interfaz para "esconder" las subrutinas detrás, por ejemplo, cuando tiene una rutina que opera en (digamos) enteros, y una en reales , y desea poder invocar el mismo nombre de rutina en cualquiera de ellos y dejar que el compilador lo resuelva según los argumentos. Dichos constructos se denominan rutinas genéricas y existen desde Fortran 90. En ese caso, se crea una interfaz explícitamente para esta nueva rutina genérica y se enumeran las interfaces con las rutinas "reales" dentro de ese bloque de interfaz.