viernes, 2 de noviembre de 2007

Interprogramación de Fortran y C

Estoy en Valencia encargado de mantener código.

Código en Fortran.

El problema de los códigos heredados, en general, es que son heredados. Uno no cuenta con sus propias costumbres de programación (indentado, nombrado de variables, comentarios en el código...) sino que tiene que adivinar sobre código ajeno.

Pero bueno, una cosa es eso, y otra Fortran. Fortran como lenguaje, tal y como se utiliza en Ciencia (códigos FORTRAN 77 heredados de estudiantes de doctorado en estudiantes de doctorado) es algo realmente asqueroso. A veces da la tentación de reprogramar en C, o de modernizar el código a Fortran 95.

La almendra de la cuestión es hacer esa reprogramación en C de rutinas que seguirán siendo llamadas desde Fortran, al estilo Fortran.

¿Funciones o subrutinas?



En C tenemos funciones. En Fortran tenemos funciones y subrutinas. Si tenemos que llamar a Fortran desde C, ¿cómo escribir en Fortran el código llamado?

Básicamente, si nuestra función en C retorna un valor, en Fortran usaremos una función. Si la función en C no retorna (void), en Fortran usaremos una subrutina.

Y viceversa, si en Fortran tenemos una llamada CALL, en C usaremos una función void, mientras que si en Fortran tenemos una llamada a función, en C usaremos una función del mismo tipo.

Nombres de funciones



Normalmente los compiladores de Fortran, en las tablas de símbolos de los ficheros objeto, cambian el nombre de los objetos a minúsculas (recordemos que en Fortran las mayúsculas y las minúsculas son equivalentes) y añaden un guión bajo al final del nombre.

Así, si desde C queremos llamar a una función o subrutina Fortran, debemos llamarla con su nombre escrito completamente en minúsculas y añadir un guión bajo al final.

Y si desde Fortran queremos llamar a una función C, ésta tiene que tener un nombre completamente en minúsculas y un guión al final, que en el código Fortran no pondremos. Si no es así, nos veremos obligados a programar en C un wrapper que siga esta convención y llame a la función C real.

Paso de variables



Es importante recordar que en Fortran las variables siempre se pasan por referencia, nunca por valor. Incluso si llamamos a una función con argumentos constantes.

Por ello, las funciones C que sean llamadas desde Fortran deben esperar que todos sus argumentos sean punteros, y las funciones o subrutinas Fortran que sean llamadas desde C deben ser llamadas proporcionándoles argumentos que sean punteros.

Hay que tener en cuenta, cuando se pasen matrices, que el nombre de la matriz, a secas, ya es un puntero en C, así que no hay que añadirle el asterisco delante.

Almacenamiento de matrices



En C las matrices se almacenan "por filas", o mejor expresado, el índice más a la derecha, el último, recorre secuencialmente los elementos de la matriz. En Fortran, en cambio, las matrices se almacenan "por columnas", es decir, el índice más a la izquierda, el primero, es el que recorre secuencialmente los elementos.

Por ello, cuando pasamos una matriz de Fortran a C o viceversa, debemos invertir el orden de todos sus índices.

También hay que tener en cuenta que mientras que en Fortran una matriz puede declararse con índices arbitrarios, que por defecto comienzan en 1, en C las matrices siempre comienzan con el índice 0.

Por la misma razón, todo programador decente de Fortran escribe bucles anidados en los que el bucle más interno recorre el primer índice, mientras que todo programador decente de C escribe bucles anidados en los que el bucle más interno recorre el último índice.

Bloques COMMON



En Fortran es común utilizar bloques COMMON como un modo de que todas las subrutinas y funciones puedan acceder a determinadas variables. Es posible hacer uso desde C de estos bloques COMMON, si tenemos en cuenta que se presentan como estructuras de datos cuyo contenido es el conjunto de variables que en C correspondan a las variables Fortran.

Es necesario tener en cuenta que lo mencionado acerca de los identificadores de funciones Fortran en C también se aplica a los nombres de estas estructuras y a los de las variables que las componen.

Es necesario fijarse con cuidado, si tenemos problemas de acceso a estas variables, en las direcciones resultantes para las variables flotantes de doble precisión. Los compiladores de C pueden añadir relleno en las estructuras de datos para que los límites de las variables se alineen correctamente, y los de Fortran no pueden hacerlo en sus bloques COMMON.