FORTRAN à l'ancienne exigeait qu'un programmeur qui voulait mettre une partie d'un tableau à la disposition d'une fonction ait besoin de passer une référence à l'ensemble du tableau, ainsi qu'une ou plusieurs valeurs entières spécifiant l'indice de départ et soit l'indice de fin, soit le nombre d'éléments . C permet de simplifier cela en passant un pointeur sur le début de la portion d'intérêt avec le nombre d'éléments. En termes directs, cela accélérerait les choses (en passant deux choses plutôt que trois). Indirectement, cependant, cela peut finir par ralentir les choses en limitant les types d'optimisation qu'un compilateur peut effectuer.
Considérez la fonction:
void diff(float dest[], float src1[], float src2[], int n)
{
for (int i=0; i<n; i++)
dest[i] = src1[i] - src2[i];
}
si un compilateur savait que chacun des pointeurs identifierait le début d'un tableau, il pourrait générer du code qui agirait sur les éléments du tableau en parallèle ou dans n'importe quel ordre, car pour tout x! = y, les opérations sur dest [x ] n'affectera pas src1 [y] ni src2 [y]. Par exemple, sur certains systèmes, un compilateur peut bénéficier de la génération de code équivalent à:
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
}
Notez que chaque opération qui charge ou calcule une valeur a au moins une opération de plus entre elle et l'opération suivante qui utilise cette valeur. Certains processeurs peuvent chevaucher le traitement de différentes opérations lorsque ces conditions sont remplies, améliorant ainsi les performances. Notez cependant que, comme un compilateur C n'a aucun moyen de savoir que le code ne passera pas de pointeurs vers des régions se chevauchant partiellement d'un tableau commun, un compilateur C ne peut pas effectuer la transformation ci-dessus. Cependant, les compilateurs FORTRAN à code équivalent pouvaient et ont fait une telle transformation.
Alors qu'un programmeur C pourrait tenter d'obtenir des performances comparables en écrivant explicitement du code qui déroulait la boucle et chevauchait les opérations des passes adjacentes, un tel code pourrait facilement dégrader les performances s'il utilisait tant de variables automatiques qu'un compilateur devait les "renverser" sur Mémoire. L'optimiseur d'un compilateur FORTRAN en connaîtrait probablement plus qu'un programmeur sur les formes d'entrelacement qui fourniraient des performances optimales dans un scénario donné, et il est souvent préférable de laisser ces décisions à ces compilateurs. Alors que C99 tentait d'améliorer quelque peu la situation de C en ajoutant un restrict
qualificatif, cela ne pouvait être utilisé ici que s'il dest[]
s'agissait d'un tableau distinct des deux src1[]
et src2[]
, ou si le programmeur avait ajouté des versions distinctes de la boucle pour gérer les cas où tout dest
était disjoint desrc1
et src2
, où src1[]
et dest
étaient égaux et src2
étaient disjoints, où src2[]
et dest[]
étaient égaux et src1
étaient disjoints, et où les trois tableaux étaient égaux. FORTRAN, en revanche, pouvait gérer les quatre cas sans difficulté en utilisant le même code source et le même code machine.