Bei FORTRAN alter Art musste ein Programmierer, der einen Teil eines Arrays für eine Funktion verfügbar machen wollte, einen Verweis auf das gesamte Array zusammen mit einem oder mehreren ganzzahligen Werten übergeben, die den Startindex und entweder den Endindex oder die Anzahl der Elemente angeben . C macht es möglich, dies zu vereinfachen, indem ein Zeiger zusammen mit der Anzahl der Elemente an den Anfang des interessierenden Abschnitts übergeben wird . Direkt ausgedrückt würde dies die Dinge schneller machen (zwei Dinge anstatt drei). Indirekt kann es jedoch zu einer Verlangsamung kommen, indem die Optimierungsarten, die ein Compiler ausführen kann, eingeschränkt werden.
Betrachten Sie die Funktion:
void diff(float dest[], float src1[], float src2[], int n)
{
for (int i=0; i<n; i++)
dest[i] = src1[i] - src2[i];
}
Wenn ein Compiler wüsste, dass jeder der Zeiger den Anfang eines Arrays identifiziert, könnte er Code generieren, der auf Elemente des Arrays parallel oder in beliebiger Reihenfolge einwirkt, da für x! = y Operationen auf dest [x ] beeinflusst weder src1 [y] noch src2 [y]. Zum Beispiel kann ein Compiler auf einigen Systemen davon profitieren, Code zu generieren, der äquivalent ist zu:
void dif(float dest[], float src1[], float src2[], int n)
{
int i=0;
float t1a,t1b,t2a,t2b,tsa,tsb;
if (n > 2)
{
n-=4;
t1a = src1[n+3]; t1b = src2[n+3]; t1b=src2[n+2]; t2b = src2[n+2];
do
{
tsa = t1a-t2a;
t1a = src1[n+1]; t2a = src2[n+1];
tsb = t2b-t2b;
dest[n+3] = tsa;
t1b = src1[n]; t2b = src2[n];
n-=2;
dest[n+4] = tsb;
} while(n >= 0);
... add some extra code to handle cleanup
}
else
... add some extra code to handle small values of n
}
Beachten Sie, dass jede Operation, die einen Wert lädt oder berechnet, mindestens eine weitere Operation zwischen sich und der nächsten Operation hat, die diesen Wert verwendet. Einige Prozessoren können die Verarbeitung verschiedener Vorgänge überlappen, wenn diese Bedingungen erfüllt sind, wodurch die Leistung verbessert wird. Beachten Sie jedoch, dass ein C-Compiler die obige Transformation nicht ausführen kann, da ein C-Compiler nicht weiß, dass der Code keine Zeiger auf teilweise überlappende Bereiche eines gemeinsamen Arrays übergeben wird. FORTRAN-Compiler, denen äquivalenter Code zugewiesen wurde, konnten und haben jedoch eine solche Transformation durchgeführt.
Während ein C-Programmierer versuchen könnte, eine vergleichbare Leistung zu erzielen, indem er explizit Code schreibt, der die Schleife abwickelt und die Operationen benachbarter Durchläufe überlappt, könnte ein solcher Code die Leistung leicht verschlechtern, wenn er so viele automatische Variablen verwendet, dass ein Compiler sie "verschütten" muss Erinnerung. Der Optimierer eines FORTRAN-Compilers weiß wahrscheinlich mehr als ein Programmierer darüber, welche Formen der Verschachtelung in einem bestimmten Szenario eine optimale Leistung erbringen würden, und solche Entscheidungen sollten häufig solchen Compilern überlassen werden. Während C99 versuchte, die Situation von C durch Hinzufügen eines restrict
Qualifizierers zu verbessern , konnte dies hier nur verwendet werden, wenn dest[]
es sich um ein von beiden src1[]
und getrenntes Array handelte src2[]
, oder wenn der Programmierer separate Versionen der Schleife hinzufügte, um die Fälle zu behandeln, in denen alle nicht dest
zusammenhängend warensrc1
undsrc2
, wosrc1[]
und dest
waren gleich und src2
waren unzusammenhängend, wo src2[]
und dest[]
waren gleich und src1
waren unzusammenhängend, und wo alle drei Reihen gleich waren. Im Gegensatz dazu konnte FORTRAN alle vier Fälle problemlos mit demselben Quellcode und demselben Maschinencode behandeln.