Die Sprachen weisen ähnliche Merkmale auf. Der Leistungsunterschied ergibt sich aus der Tatsache, dass in Fortran Aliasing nicht erlaubt ist, es sei denn, es wird eine EQUIVALENCE-Anweisung verwendet. Jeder Code, der Aliasing enthält, ist kein gültiger Fortran-Code, aber es ist Sache des Programmierers und nicht des Compilers, diese Fehler zu erkennen. Daher ignorieren Fortran-Compiler mögliche Aliasing-Fehler von Speicherzeigern und ermöglichen es ihnen, effizienteren Code zu erzeugen. Werfen Sie einen Blick auf dieses kleine Beispiel in C:
void transform (float *output, float const * input, float const * matrix, int *n)
{
int i;
for (i=0; i<*n; i++)
{
float x = input[i*2+0];
float y = input[i*2+1];
output[i*2+0] = matrix[0] * x + matrix[1] * y;
output[i*2+1] = matrix[2] * x + matrix[3] * y;
}
}
Diese Funktion würde nach der Optimierung langsamer laufen als das Fortran-Pendant. Warum ist das so? Wenn Sie Werte in das Ausgabe-Array schreiben, können Sie die Werte der Matrix ändern. Schließlich könnten sich die Zeiger überschneiden und auf denselben Speicherbereich zeigen (einschließlich der int
Zeiger!). Der C-Compiler ist gezwungen, die vier Matrixwerte für alle Berechnungen neu aus dem Speicher zu laden.
In Fortran kann der Compiler die Matrixwerte einmal laden und sie in Registern speichern. Dies ist möglich, weil der Fortran-Compiler davon ausgeht, dass sich Zeiger/Arrays im Speicher nicht überschneiden.
Glücklicherweise ist die restrict
Schlüsselwort und strict-aliasing wurden in den C99-Standard aufgenommen, um dieses Problem zu lösen. Heutzutage wird es auch von den meisten C++-Compilern gut unterstützt. Mit dem Schlüsselwort können Sie dem Compiler einen Hinweis geben, dass der Programmierer verspricht, dass ein Zeiger nicht mit einem anderen Zeiger verwechselt werden darf. Striktes Alias bedeutet, dass der Programmierer verspricht, dass sich Zeiger unterschiedlichen Typs niemals überschneiden werden, z. B. ein double*
überschneidet sich nicht mit einer int*
(mit der besonderen Ausnahme, dass char*
y void*
kann sich mit allem überschneiden).
Wenn Sie diese verwenden, erhalten Sie die gleiche Geschwindigkeit von C und Fortran. Allerdings ist die Möglichkeit, die restrict
Schlüsselwort nur bei leistungskritischen Funktionen bedeutet, dass C- (und C++-) Programme viel sicherer und einfacher zu schreiben sind. Betrachten Sie zum Beispiel den ungültigen Fortran-Code: CALL TRANSFORM(A(1, 30), A(2, 31), A(3, 32), 30)
die von den meisten Fortran-Compilern problemlos und ohne Warnung kompiliert wird, aber einen Fehler verursacht, der nur bei einigen Compilern, auf bestimmter Hardware und mit bestimmten Optimierungsoptionen auftritt.