Mischen C und Fortran

Mischen von C und Fortran

Beim Mischen von C- und Fortran-Routinen in einem Programm sollte man folgende Punkte beachten:

1. Namensgebung der Routinen

2. Parameterübergabe

3. Felder

4. COMMON-Blöcke oder Globale Variable

5. Wrapper

1. Namensgebung der Routinen:

In der Sprache C wird der Name so übernommen, wie er im Source-Code angegeben wurde.

In Fortran werden im Default-Fall (case insensitiv) alle Buchstaben des Routinenamens in Kleinbuchstaben umgewandelt. Ausnahme: Wenn mit der Compiler-Option -U übersetzt wird (case sensitiv), werden die Buchstaben nicht verändert. Es ist wichtig zu wissen, dass der f77-Compiler immer noch ein "_" an den Routinenamen anfügt.

Daraus folgt:

Ruft man von einem C-Programm aus eine Fortran-Routine auf, so muss beim Aufruf im C-Code ein Underscore ("_") als Namensschluss stehen.

 ivar1 = function_name_ (ivar2);
INTEGER FUNCTION FUNCTION_NAME (IVAR)

Ruft man von einem Fortran-Programm aus eine C-Routine auf, so muss diese bei der Definition mit einem Underscore aufhören.

 CALL C_ROUTINE(VAR)
void c_routine_(double *var);

Manche System-Unterprogramme sind mit beiden Namen vorhanden, mit und ohne Underscore, und damit sieht es so aus, als könne man ein und dieselbe System-Routine aus beiden Sprachen aufrufen. Dies trifft jedoch nicht zu. Beispiel: Die System-Routine "system" gibt es in libc.so und als "system_" in libftn.so, mit jeweils gleicher Leistung.

2. Parameterübergabe:

Bei der Kopplung C/Fortran dürfen in Fortran nur die Namen von Variablen, Feldern oder Matrix-Elementen übergeben werden. Dies bewirkt, dass die Werte auf der C-Seite wie "call-by-address" übergeben werden.

In C werden die Variablen mit "call-by-value" und die Felder mit "call-by-address" übergeben. Dies muss bei der Definition der Übergabeparameter bei der Definition der C-Routinen berücksichtigt werden (Pointer).

Die kompatiblen Typen für Unterprogramme sind:

Fortran

C

Bemerkung

integer*2 x

short int *x;

 

integer x

int *x; oder: long int *x;

a)

logical x

int *x; oder: long int *x;

a)

real x

float *x;

 

double precision x

double *x;

a),b)

complex x

struct{float real,imag;}x;

 

double complex x

struct{double real,imag;}x;

 

character*6 x

char x[6];

c)

a) Sind auch als Rückgabewerte von Funktionen zulässig, dürfen dann aber nicht als Pointer in C definiert werden. Zum Beispiel:

  integer function name()          int name_(); 

b) Fortran-Funktion REAL, dennoch Definition in C mit double precision:

  real funktion name()             double name_(); 

c) char-Felder sind nicht voll kompatibel.

Außerdem muss in den Routinen beachtet werden, dass für C das letzte Zeichen mit einem 0-Oktett besetzt ist, auch wenn es in Fortran nicht benötigt wird.

Bsp.:

    string(l:l) = char(0) 

3. Felder:

Felder werden in Fortran spaltenweise und in C zeilenweise im Speicher abgelegt.

Beispiel:

Matrix:

a(1,1)

a(1,2)

a(1,3)

 

a(2,1)

a(2,2)

a(2,3)

Die Werte liegen wie folgt im Speicher direkt hintereinander:

Fortran:

a(1,1)

a(2,1)

a(1,2)

a(2,2)

a(1,3)

a(2,3)

C:

a(1,1)

a(1,2)

a(1,3)

a(2,1)

a(2,2)

a(2,3)

Daraus folgt, dass 2- und mehrdimensionale Felder vor der Übergabe C<->Fortran umgeordnet werden müssen.

4. COMMON-Blöcke oder Globale Variable

COMMON-Blöcke in Fortran und globale Variablen in C werden in die gleichen Speicherbereiche des Rechners abgelegt. Der Fortran-Compiler fügt an den Namen des COMMON-Blockes noch ein Underscore "_" an. So können diese Speicherbereiche mit Namen von Routinen beider Sprachen angesprochen werden, nur sollte man auf die Namensgebung achten.

Beispiel:

Fortran                       C
... ...
subroutine x() /+-> struct S{int ig; float fg;}bl_;
integer ic / void y(){
integer ip / int ip;
real fc / float fp;
real fp / ...
common /bl/ ic,fc <-+ ...
... ...
ip=ic ip = l_.ig;
fp=fc fp = bl_.fg;
... ...
end }

5. Wrapper:

Wenn man von C-Routinen aus vorgegebene Fortran-Routinen aufrufen möchte, kann man mit der Sprache C alle Anpassungen vornehmen, zum Beispiel "_" bei der Namensgebung beim Aufruf, call-by-address usw..

Eine Anpassung mit Fortran ist jedoch nicht möglich, wenn von Fortran aus vorgegebene C-Routinen aufgerufen werden sollen. Dazu dienen die Programme

"mkf2c" und "as".

Vorgehen:

1. Man schreibt das Fortran-Programm und ruft die C-Routine darin auf wie eine Fortran-Routine. Anschließend übersetzt man nur mit der Option -c, um das Object-File zu erhalten, z.B.: "f.o" .

Beispiel: f77 -c f.f

Quelle in Datei f.f:

              program t
character*8 a,b
C die C-Routine strncmp vergleicht Characterstrings miteinander
integer i,j
integer strncmp
external strncmp
a = '12345678'
b = '01234567'
i = 8
j = strncmp(a,b,i)
write(*,*) j
end

2. Die C-Routine liege als Object-File vor oder man schreibt eine C-Funktion und übersetzt sie mit -c, um ein Object-File, z.B.: "c.o", zu erhalten.

3. Um den C-Modul mit dem Fortran-Modul zu verbinden, stellt man das Verbindungsprogramm her, den Wrapper. Es ist ebenfalls ein Object-File, z.B.: "s.o" .

Diese drei Object-Files bindet man anschließend:

    f77 -o prog f.o c.o s.o

oder, für obiges Beispiel, da die Routine "strncmp" in der C-Standard-Lib enthalten ist:

    f77 -o prog f.o s.o

Erstellung des Verbindungsprogramms:

A) Man erstellt eine Beschreibungsdatei der C-Routine in einer Datei mit der Endung ".fc". Die Beschreibungsdatei enthält nur die C-Definition der gewünschten Routine, ohne Semikolon, dafür aber mit einem Paar geschweifter Klammern.

Zum Beispiel wird in die Datei "s.fc" folgendes geschrieben:

    int strncmp(char *a, char *b, int n){}

B) Mit dem Kommando "mkf2c" stellt man aus der Beschreibungsdatei eine Assembler-Quelle her, wobei die Option -l für Routinenamen größer als 6 Zeichen wichtig ist. Das erste Argument ist der Name der Beschreibungsdatei, das zweite der Name der zu erstellenden Assembler-Quell-Datei.

Beispiel:

    mkf2c -l s.fc s.s

C) Die Assemblerquelle übersetzt man mit den Optionen -KPIC. Beispiel:

    as -KPIC -o s.o s.s

(Mit mehrdimensionalen Feldern wurde der Wrapper noch nicht getestet.)

Bei Fragen und Problemen wenden Sie sich bitte an Dr. Corr, Tel.: 3075