Zum Inhalt springen

Fortran: Fortran und C: Fortran 2003

Aus Wikibooks
<<< zur Fortran-Startseite
<< Fortran und C F >>
< Fortran 90/95 und C Fortran 2003 und C >


Ab Fortran 2003 ist es viel einfacher auf C zu zugreifen, als in Fortran 95. Es wurde im Fortran 2003-Standard ein intrinsisches Modul namens iso_c_binding vorgesehen, das die zum Zugriff auf C-Programme nötigen Elemente enthält. Fortran 2018 und 2023 brachten einige Erweiterungen zu diesem Thema. Darauf wird aber vorerst hier nicht eingegangen.

Folgende Beispiele wurden unter dem Betriebssystem OpenSUSE Leap 15.6 gestestet. Zum Einsatz kamen der gfortran-Compiler (7.5.0, 2017) und Intels ifx (2025.2.0).

Ein einfaches Beispiel

[Bearbeiten]

Fortran 2003-Code: bsp.f90

Fortran 2003 (oder neuer)-Code
program bsp
  implicit none 

  interface
    function addition( a, b ) bind( c )
      use, intrinsic :: iso_c_binding
      real( kind = c_float ), value :: a
      real( kind = c_float ), value :: b
      real( kind = c_float )        :: addition
    end function addition
  end interface

  write (*,*) addition( 2.5, 3.3 )

! Ausgabe:  5.8  
end program bsp

C-Code: bsp.c

Programmcode
float addition(float a, float b)
{
  return (a + b);  
}

Makefile:

Programmcode
FC = gfortran # oder ifx
CC = gcc

bsp: bsp_c.o bsp_f90.o
	$(FC) -o bsp bsp_c.o bsp_f90.o

bsp_c.o: bsp.c
	$(CC) -c -o bsp_c.o bsp.c

bsp_f90.o: bsp.f90
	$(FC) -c -o bsp_f90.o bsp.f90

.PHONY: clean
clean:
	rm *.o


Was ist neu gegenüber Fortran 95?

  • bind( c )
... bind-Attribut, stellt unter anderem die Interoperabilität mit C bezüglich Prozedurnamenskonventionen nach der Übersetzung sicher
  • use, intrinsic :: iso_c_binding
... Einbindung des intrinsischen Moduls iso_c_binding
  • real( kind = c_float )
... C-Datentyp float
  • value
... call by value

Datentyp-Zuordnung

[Bearbeiten]

Das iso_c_binding-Modul stellt benannte Konstanten zur Verfügung, die bei Fortran-Datentypen als kind-Wert zu verwenden sind, um den jeweiligen C-Datentyp zu charakterisieren. Weist eine solche Konstante einen negativen Wert auf, dann ist keine Entsprechung von Fortran-Datentyp zu C-Datentyp vorhanden.

Fortran-Datentyp Benannte iso_c_binding-Konstante (kind-Wert) C-Datentyp
integer c_int int
c_short short int
c_long long int
c_long_long long long int
c_signed_char signed char, unsigned char
c_size_t size_t
c_int8_t int8_t
c_int16_t int16_t
c_int32_t int32_t
c_int64_t int64_t
c_int_least8_t int_least8_t
c_int_least16_t int_least16_t
c_int_least32_t int_least32_t
c_int_least64_t int_least64_t
c_int_fast8_t int_fast8_t
c_int_fast16_t int_fast16_t
c_int_fast32_t int_fast32_t
c_int_fast64_t int_fast64_t
c_intmax_t intmax_t
c_intptr_t intptr_t
real c_float float
c_double double
c_long_double long double
complex c_float_complex float _Complex
c_double_complex double _Complex
c_long_double_complex long double _Complex
logical c_bool _Bool
character c_char char
Quelle: J3/04-007 Fortran 2003 Working Draft

Das iso_c_binding-Modul stellt keine speziellen kind-Werte für unsigned-Integer-Datentypen zur Verfügung. Im Bedarfsfall sind die entsprechenden kind-Werte für die signed-Datentypen zu verwendet.

Nicht jeder Fortran-Compiler unterstützt alle genannten C-Datentypen und die unterstützten Datentypen können sich compilerspezifisch in der Byteanzahl unterscheiden.

„call by value“ vs. „call by reference“

[Bearbeiten]

Im einführenden Beispiel wurden die Funktionsargumente „call by value“ übergeben. Das Variablenattribut value stellt dieses Verhalten sicher. Wird dieses Attribut nicht gesetzt, so gilt „call by reference“.

Beispiel:

Fortran-Code bsp.f90:

Fortran 2003 (oder neuer)-Code
program bsp
  implicit none
 
  interface
    subroutine zahl( a, b ) bind( c )
      use, intrinsic :: iso_c_binding
      integer( kind=c_int ), value :: a
      integer( kind=c_int )        :: b
    end subroutine zahl
  end interface
 
  call zahl(5, 7)

! Ausgabe:  
!   Ergebnis = 35
end program bsp 


C-Code bsp.c:

Programmcode
#include <stdio.h>
 
void zahl(int a, int *b)
{
  printf("%s%d\n", "Ergebnis = ", a * *b);
}

Globale C-Variablen

[Bearbeiten]

Muss in Fortran auf globale C-Variablen zugegriffen werden, so sind diese im Gültigkeitsbereich eines Fortran-Modul zu spezifizieren.

Felder

[Bearbeiten]

Interoperabilität zwischen Fortran und C ist nur mit Feldern definierter Größe gegeben. Allozierbare Felder oder Zeigerfelder sind nicht erlaubt.


Beispiel:

Fortran 2003 (oder neuer)-Code
program bsp
  implicit none 

  integer, dimension( 3 ) :: a = (/ 1, 2, 3 /)

  interface
    subroutine feld1( f ) bind( c )
      use, intrinsic :: iso_c_binding
    
      integer( c_int ), dimension(*) :: f
    end subroutine feld1   
  end interface  

  write (*,*) "Feld a vorher: ", a
  call feld1( a )  
  write (*,*) "Feld a nachher: ", a  
  
! Ausgabe:
!   Feld a vorher:  1 2 3
!   Feld a nachher:  999 2 3 
end program bsp


Programmcode
void feld1(int f[])
{
   f[0] = 999;   
}

Übergabe von Zeichenketten

[Bearbeiten]

Beispiel:

Fortran-Code bsp.f90:

Fortran 2003 (oder neuer)-Code
program bsp
  use, intrinsic :: iso_c_binding
  implicit none 

  interface
    subroutine string1( str_in ) bind( c )
      use, intrinsic :: iso_c_binding
    
      character( kind=c_char, len=1 ) :: str_in ! Ungültiges Fortran 2003 da nur len=1 erlaubt ist
    end subroutine string1   
  end interface  
  
  call string1( c_char_"Greetings from Fortran" // c_null_char )  
  
! Ausgabe:
!   "Greetings from Fortran" 
end program bsp


C-Code bsp.c:

Programmcode
#include <stdio.h>

void string1(char str_in[])
{
  printf("%s \n", str_in);
}


Für len=1 funktioniert das Beispiel mit allen angeführten Compilern. Das len-Attribut kann im Übrigen auch weggelassen werden; einige unterstützen als compilerspezifische Erweitungen auch andere Längen. Im Fortran 2003-Working-Draft wird in „Note 15.23“ eine andere Möglichkeit für die Übergabe von Zeichenketten angeführt. Diese folgt im wesentlichen der Annahme:

C-Zeichenketten sind char-Felder mit einem terminierenden \0-Zeichen und können deshalb in Fortran als Felder vom Datentyp character mit einem kind-Wert c_char angesprochen werden.

Daher wird im Interface der Dummy-Parameter in Form eines Feldes aus Zeichen des Typs c_char deklariert. Das entspräche auch genau der aufzurufenden C-Funktion. Allerdings ist solcherart verfasster Code dann nicht mit allen Compilern übersetzbar.


Beispiel:

Fortran-Code bsp.f90:

Fortran 2003 (oder neuer)-Code
program bsp
  use, intrinsic :: iso_c_binding
  implicit none 

  interface
    subroutine string1( str_in ) bind( c )
      use, intrinsic :: iso_c_binding
    
      character( kind=c_char ), dimension(*) :: str_in
    end subroutine string1   
  end interface  
  
  call string1( c_char_"Greetings from Fortran" // c_null_char )  
  
! Ausgabe:
!   "Greetings from Fortran" 
end program bsp

Benannte iso_c_binding-Konstanten für Zeichen mit spezieller Bedeutung in C:

Benannte Konstante Wert
c_null_char '\0'
c_alert '\a'
c_backspace '\b'
c_form_feed '\f'
c_new_line '\n'
c_carriage_return '\r'
c_horizontal_tab '\t'
c_vertical_tab '\v'

Enumerationen

[Bearbeiten]

Mit Fortran 2003 sind auch in dieser Programmiersprache Enumerationen (Aufzählungstypen) möglich. Die Werte in einer solchen Enumeration besitzen einen integer-Datentyp. Der kind-Wert ist nicht festgelegt, wird jedoch so gewählt, dass im Rahmen der jeweiligen Möglichkeiten alle Enumeratoren erfasst sind.

Die von C-Enumerationen bekannten Eigenschaften gelten gleichermaßen für Fortran-Enumerationen, z.B.:

  • ohne explizite Zuweisung von Werten wird mit dem Wert 0 gestartet.
  • ohne explizite Zuweisung von Werten wird in der Anordnungsreihenfolge der Elemente sukzessiv immer um 1 hochgezählt.
  • Wurde dem Vorgängerelement eine Ganzzahl zugewiesen, dem Element jedoch nicht, so ist der Wert dieses Elementes die dem Vorgängerelement zugeordnete Ganzzahl + 1.


Beispiel:

Fortran-Code bsp.f90:

Fortran 2003 (oder neuer)-Code
program bsp
  implicit none 

  enum, bind(c) 
    enumerator :: MO=1, DI=2, MI=3, DO=4, FR=5, SA=6, SO=7
  end enum  
  
  interface
    subroutine tag( w ) bind( c )
      use, intrinsic :: iso_c_binding

      integer( c_int ), value :: w
    end subroutine tag
  end interface
      
  call tag(MI);    

! Ausgabe:
!   Mittwoch
end program bsp


C-Code bsp.c:

Programmcode
#include <stdio.h>

typedef enum {
  MO=1, DI=2, MI=3, DO=4, FR=5, SA=6, SO=7
} wochentag;


void tag(wochentag w)
{
  switch(w)
  {
    case MO:
      printf("Montag\n");
      break;
    case DI:
      printf("Dienstag\n");
      break;
    case MI:
      printf("Mittwoch\n");
      break;
    case DO:
      printf("Donnerstag\n");
      break;
    case FR:
      printf("Freitag\n");
      break;
    case SA:
      printf("Samstag\n");
      break;
    case SO:
      printf("Sonntag\n");
      break;
    default:
      printf("Kein Tag\n");      
  }
}

Zeiger

[Bearbeiten]

Für das C-Zeiger-Handling stellt Fortran 2003 im iso_c_binding-Modul den Datenverbund c_ptr und einige Unterprogramme bereit.

UP Beschreibung
l = c_associated ( c_ptr1 [, c_ptr2] ) Prüft den Assoziationsstatus von c_ptr1. Diese Funktion ermittelt also, ob c_ptr1 überhaupt assoziert ist, oder ob c_ptr1 mit c_ptr2 assoziert ist.
c_ptr = c_loc ( x ) Gibt die Adresse von x zurück.
c_f_pointer (  c_ptr, fptr [, shape] ) Wandelt einen C-Zeiger c_ptr in einen Fortran-Zeiger fptr um. Die Vorgabe von shape ist nur dann erforderlich und möglich, wenn fptr ein Feld ist. fptr ist intent( inout ).


Beispiel:

Fortran-Code bsp.f90:

Fortran 2003 (oder neuer)-Code
module cglob
  use, intrinsic :: iso_c_binding

  type( c_ptr ), bind( c )                :: ptr1, ptr2, ptr3
  real( kind=c_float ), target, bind( c ) :: a, b
end module cglob

program bsp
  use cglob
  implicit none 
      
  real, pointer :: p => null()
      
! *** Zuordnungsstatus ***      
  write (*,*) "Ist ptr1 assoziert? ", c_associated( ptr1 )
  write (*,*) "Ist ptr2 assoziert? ", c_associated( ptr2 )
  write (*,*) "Ist ptr2 mit ptr3 assoziert? ", c_associated( ptr2, ptr3 )
  write (*,*) "Ist ptr2 mit &a assoziert? ", c_associated( ptr2, c_loc(a) )
  
! *** Wert von ptr2? ***
  call c_f_pointer( ptr2, p )
  write (*,*) "Wert von ptr2? ", p 

! *** ptr1 neu setzen ***
  ptr1 = c_loc( b )

! *** Wert von ptr1 ***
  call c_f_pointer( ptr1, p )
  write (*,*) "Wert von ptr1? ", p 
  
! Ausgabe:
!   Ist ptr1 assoziert?  F
!   Ist ptr2 assoziert?  T
!   Ist ptr2 mit ptr3 assoziert?  F
!   Ist ptr2 mit &a assoziert?  T
!   Wert von ptr2 (bzw. p)?  5555.66
!   Wert von ptr1 (bzw. p)?  -12.3   
end program bsp


C-Code bsp.c:

Programmcode
float a = 5555.66;
float b = -12.3;

float *ptr1 = 0;
float *ptr2 = &a;
float *ptr3 = &b;


Nun ist die Zeiger-Verwendung wie im obigen Beispiel skizziert, eher die Ausnahme als die Regel. Wesentlich häufiger trifft man Zeiger in C-Bibliotheken im Zusammenhang mit Funktionen an. Dort dienen sie aus Anwendersicht als return-Werte oder der Parameterübergabe „call-by-reference“. Oft sind dabei auch Zeiger auf Strukuren im Spiel. Näheres dazu folgt im nächsten Abschnitt.

Für C-Zeiger auf den Wert NULL bietet das ISO-C-Binding-Modul die Konstante C_NULL_PTR.

Datenverbund

[Bearbeiten]

Die einzelnen Datenelemente der Struktur / des Datenverbundes müssen in Fortran und C selbstverständlich äquivalenten Datentyp aufweisen. Die Bezeichnungen der jeweiligen Datenelemente müssen nicht beibehalten werden. Sehr wohl müssen aber die Positionen der Einzelelemente im Fortran-Datenverbund der nachzubildenden C-Struktur entsprechen.

Für die Gewährleistung der Interoperabilität darf ein an C gebundener Datenverbund in Fortran (struct) keine Zeiger mit dem pointer-Attribut oder allozierbaren Felder als Datenelemente enthalten. Sind in der C-Struktur Zeiger vorhanden, so sind diese im entsprechenden Fortran-Datenverbund mittels type( c_ptr ) zu beschreiben.

Für Bitfelder oder Unions gibt es in Fortran keine entsprechenden Gegenstücke.


Beispiel:

Fortran 2003 (oder neuer)-Code
module cglob
  use, intrinsic :: iso_c_binding

  type, bind( c ) :: verbund
    integer( kind=c_int ) :: a
    real( kind=c_float )  :: b
  end type verbund

  type(verbund), bind( c ) :: v  
end module cglob

program bsp
  use cglob
  implicit none 

  interface
    subroutine set_v( a_in, b_in) bind( c )
      use, intrinsic :: iso_c_binding
    
      integer( c_int ), value :: a_in
      real( c_float ), value :: b_in
    end subroutine set_v

    
    subroutine print_v() bind( c )
    end subroutine print_v
    
  end interface  

  call set_v( 5, -10.9)  
  call print_v()
  write (*,*) "Fortran-Ausgabe: ", v  
  v%a =  99
  call print_v()
  write (*,*) "Fortran-Ausgabe: ", v  

! Ausgabe:
!   C-Ausgabe: 5  -10.900000
!    Fortran-Ausgabe:  5 -10.9
!   C-Ausgabe: 99  -10.900000
!    Fortran-Ausgabe:  99 -10.9
end program bsp


Programmcode
#include <stdio.h>

typedef struct {
  int a;
  float b;
} verbund;

verbund v;

void set_v(int a_in, float b_in)
{
  v.a = a_in;
  v.b = b_in;  
}

void print_v()
{
  printf("C-Ausgabe: %i  %f\n", v.a, v.b);
}


Beispiel: Struktur als Rückgabewert und Argument einer Funktion - Teil 1

Bekannt seien zwei Funktionsprototypen in der Programmiersprache C:

Xyz *get_xyz();

und

void set_xyz(Xyz *x); 

Xyz sei ein C-struct, dessen Inhalt hier nicht näher interessiert.


Die Schnittstelle, mit dem in Fortran die C-Anbindung der Funktionen realisiert wird, könnte so aussehen:

interface
  function get_xyz() bind( c )
    use, intrinsic :: iso_c_binding
    type( c_ptr )  :: get_xyz
  end function get_xyz

  subroutine set_xyz( x ) bind( c )
    use, intrinsic :: iso_c_binding
    type( c_ptr ), value  :: x
  end subroutine set_xyz
end interface

Und schon können diese Funktionen auch in Fortranroutinen direkt Anwendung finden, z.B:

type( c_ptr ) :: x56

x56 = get_xyz()
call set_xyz( x56 )
 

Wie man anhand dieses Beispiels erkennt, ist die interne Struktur von Xyz in diesem Fall vollkommen irrelevant. Es ist nicht nötig, in der API-Dokumentation oder in den C-Headerdateien nachzuforschen, wie der C-struct konkret aufgebaut ist. Für den Fortran-Programmierer ist dies immer ein type( c_ptr ) (natürlich nur, solange Zeiger auf Strukturen gefordert sind). Wird ein Zeiger des Typs c_ptr nur via Fortranprogramm zwischen verschiedenen C-Funktionen übergeben oder zurückgeliefert, so ist auch keine Umwandlung in einen Fortran-Zeiger erforderlich und wäre mangels genauer Kenntnis des Aufbaus von Xyz hier auch nicht möglich. Erst dann, wenn von Fortran aus auf einzelne Elemente eines C-struct zugegriffen werden soll oder mit Kopien der Struktur hantiert wird, muss diese Struktur in Fortran nachgebaut werden.


Beispiel: Struktur als Rückgabewert und Argument einer Funktion - Teil 2

Fortran 2003 (oder neuer)-Code
module test
  use, intrinsic :: iso_c_binding
  implicit none
  
  
  type, bind( c ) :: A
  ! Das funktioniert nicht mit allen Kompilern; versuchen Sie ansonsten:
  !   type A
  !   sequence
    integer( c_int ) :: xc, yc
    type( c_ptr )    :: str
  end type

  interface
    function get_a() bind( c )
      use, intrinsic :: iso_c_binding
      type( c_ptr ) :: get_a 
    end function get_a

    subroutine print_a( x ) bind( c )
      use, intrinsic :: iso_c_binding
      type( c_ptr ), value :: x  
    end subroutine print_a
  end interface
end module test


program main
  use test
  implicit none

  type( c_ptr )               :: x
  type( A ), pointer          :: fptr
  character( len=9 ), pointer :: strptr

  x = get_a()
  
! C-Ausgabe
  call print_a( x )
!  Ausgabe:
!    x = 5
!    y = 997
!    str = Irgendwas

! Fortran-Ausgabe
  call c_f_pointer( x, fptr)
  call c_f_pointer( fptr%str, strptr )  ! <--- Fehlerquelle bei gfortran
  write(*,*) fptr%xc, fptr%yc, strptr
!  Ausgabe
!    5 997 Irgendwas
end program main


Programmcode
#include <stdlib.h>
#include <stdio.h>


typedef struct
{
  int x;
  int y;
  const char *str;
} A;


A *get_a()
{
  A *a = ( A * )malloc( sizeof( A ) ); 
  
  a->x = 5;
  a->y = 997;
  a->str = "Irgendwas";

  return a;
}


void print_a( A *v )
{
  printf("x = %d\n", v->x);
  printf("y = %d\n", v->y);
  printf("str = %s\n", v->str);
}

Bei der Umwandlung des C-String-Zeigers in einen Fortran-Zeiger ist die genaue Stringlänge erforderlich. Ist diese zu klein gewählt, so ist nur ein Teil des C-Strings über den Fortran-Zeiger sichtbar. Wird diese Stringlänge zu groß gewählt, dann wird diese Länge auch voll ausgenutzt und nach dem eigentlich gewünschten String folgen noch ein Menge x-beliebige Zeichen, da in Fortran der C-String-Begrenzer \0 nicht die Bedeutung wie in C besitzt.


Im obigen Beispiel wurde die Speicherplatzreservierung und Wertebelegung für eine Variable des Typs A in einer C-Funktion erledigt. Nun soll diese Aufgabe im Fortran-Programm wahrgenommen werden und dann diese in Fortran mit Werten belegte Variable an die print_a-Funktion übergeben werden. Kein Problem, möchte man im ersten Augenblick meinen. Doch der c_ptr-Typ im Datenverbund für den Zeiger auf eine Zeichenkette macht Probleme. Der g95-Compiler duldet bspw. in der c_loc-Funktion keine Zeichenketten mit einer Länge größer als 1. Der Compiler "castet" auch nicht von selbst im Datenverbundkonstruktor eine Zeichenkette in den Typ c_ptr. Eine Möglichkeit, diese Probleme zu umgehen, besteht darin, einfach einer C-Funktion einen String zu übergeben und die Adresse dieses Strings zurückgeben zu lassen. Diese Variante wird auch im folgenden Beispiel verwendet.


Beispiel: Struktur als Rückgabewert und Argument einer Funktion - Teil 3

Fortran 2003 (oder neuer)-Code
module test
  use, intrinsic :: iso_c_binding
  implicit none
  
  type, bind( C ) :: A
    integer( c_int ) :: xc, yc
    type( c_ptr )    :: str
  end type

  type( A ), target  :: a1          

  interface
    subroutine print_a( x ) bind( c )
      use, intrinsic :: iso_c_binding
      type( c_ptr ), value :: x
    end subroutine print_a
    
    function c_string_addr( s ) bind( c )
      use, intrinsic :: iso_c_binding
      character( c_char ) :: s
      type( c_ptr )       :: c_string_addr
    end function c_string_addr    
  end interface
end module test


program main
  use test
  implicit none

  character( len = 30 ) :: str
  
  str =  "Das ist ein Beispiel" // C_NULL_CHAR 

  a1 = A( 14, 56, c_string_addr( str ) )
  
  call print_a( c_loc( a1 ) )
!  Ausgabe:
!    x = 14
!    y = 56
!    str = Das ist ein Beispiel
end program main


Programmcode
#include <stdlib.h>
#include <stdio.h>


typedef struct
{
  int x;
  int y;
  const char *str;
} A;


void print_a( A *v )
{
  printf("x = %d\n", v->x);
  printf("y = %d\n", v->y);
  printf("str = %s\n", v->str);
}

char *c_string_addr( char *str )
{
  return str;
}

Problematische Kamelhöckerschreibweise?

[Bearbeiten]

C ist case-sensitive, Fortran nicht. Oft sind Funktionen in C-Bibliotheken in der  Kamelhöckerschreibweise vorzufinden, z.B.

void writeHallo();

Die Einbindung dieser C-Funktion in ein Fortran-Programm mit

 interface
   subroutine writeHallo() bind(c)
   end subroutine writeHallo
 end interface

könnte beim Linken eine Fehlermeldung der Art

undefined reference to `writehallo'

liefern.

Was ist passiert? Wie schon angedeutet, ist Fortran case-insensitive. Für einen Fortran-Compiler ist writeHallo gleich writehallo oder WRITEHaLLO. Für einen C-Compiler wären das alles unterschiedliche Funktionsbezeichner. Also wandelt der Fortran-Compiler die "unnütze" Groß-/Kleinschreibung in eine einheitliche Schreibweise um und der C-Compiler nicht. Dementsprechend findet der Linker auch keine Funktion writehallo. Es gibt eben nur die nicht-idente C-Funktion writeHallo.

Aber auch für dieses Problem gibt es in Fortran eine Lösung. Mit dem bind-Attribut können zusätzlich auch noch Labels (Benennungen) vergeben werden, z.B.:

bind( c, name="xyz" )

Solche Labels in Stringform sind nicht von der "Kopf ab"-Strategie des Fortran-Compilers betroffen. Das ist keine C-Binding-Spezialität, sondern trifft generell für alle Zeichenketten zu. Ein

 interface
   subroutine writeHallo() bind(c, name="writeHallo")
   end subroutine writeHallo
 end interface

sollte das beschriebene Link-Problem lösen.

Sonstiges

[Bearbeiten]
  • Auch C-Funktionszeiger kennt das iso_c_binding-Modul. Zu diesem Zwecke gibt es den Datenverbund c_funptr, einige Umwandlungsfunktionen ähnlich jenen im Abschnitt Zeiger behandelten und die Konstante C_NULL_FUNPTR.



<<< zur Fortran-Startseite
<< Fortran und C F >>
< Fortran 90/95 und C Fortran 2003 und C >