Mostrando entradas con la etiqueta C. Mostrar todas las entradas
Mostrando entradas con la etiqueta C. Mostrar todas las entradas

sábado, 17 de julio de 2010

Interprogramación de Fortran y C (II)

Hace relativamente poco tiempo, un mes o dos, buscando cómo hacer funcionar la biblioteca libdl en Fortran, me tropecé con este artículo de Aleksandar Donev, en el que explica muy rápidamente cómo hacerlo, y además de un modo que facilita la interprogramación entre Fortran y C en general.

Básicamente, comienza creando las rutinas que usaremos para pasar cadenas de caracteres de C (terminadas en \0) a Fortran (con indicación de longitud) y viceversa. A continuación crea las interfaces Fortran para las principales funciones de libdl y luego muestra un ejemplo.

Sencillo, conciso y correcto.

Claro que no funciona «nada más sacarlo de la caja», por dos razones. Por un lado, utiliza punteros a funciones, algo que entró en Fortran 2003 (en C lo tenemos «de toda la vida»). Y por otro, los valores RTLD_LAZY, RTLD_NOW, RTLD_GLOBAL y RTLD_LOCAL hay que hallarlos a mano antes de empezar. Pero eso no cuesta nada.

Finalmente, lo mejor de todo es que el Sr. Donev me ha autorizado a usar no solamente su método sino el código que presenta en la página. En sus propias palabras:

The code is available with absolutely no restrictions: feel free to incorporate it into your software.

El código está disponible absolutamente sin restricciones. Siéntase libre de usarlo en su propio programa.

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.