Vous voyez, dans les situations qui ont vraiment de l'importance du point de vue des performances, comme l'appel de la fonction à plusieurs reprises de nombreuses fois dans un cycle, la performance pourrait ne pas être différent.
Cela peut paraître étrange pour les gens, qui sont utilisés à la réflexion sur le code C que quelque chose exécuté par un résumé C machine dont le "langage machine" reflète fidèlement le langage C lui-même. Dans un tel contexte, "par défaut" un appel indirect à une fonction est en effet plus lent qu'un direct, parce que c'officiellement implique un supplément d'accès à la mémoire afin de déterminer la cible de l'appel.
Cependant, dans la vraie vie, le code est exécuté par une machine réelle et compilé par un compilateur d'optimisation, qui a une assez bonne connaissance de la sous-tendent l'architecture de la machine, ce qui lui permet de générer de la plus optimale de code pour cette machine. Et sur de nombreuses plates-formes, il peut s'avérer que le moyen le plus efficace pour effectuer un appel de fonction à partir d'un cycle de fait résultats identiques code pour à la fois directe et indirecte à l'appel, conduisant à la performance identique des deux.
Considérons, par exemple, la plate-forme x86. Si nous ", littéralement" traduire directs et indirects appel en code machine, nous pourrions nous retrouver avec quelque chose comme ceci
// Direct call
do-it-many-times
call 0x12345678
// Indirect call
do-it-many-times
call dword ptr [0x67890ABC]
Le premier utilise un opérande immédiat dans l'instruction machine et est en effet normalement plus rapide que ce dernier, qui doit lire les données à partir de certains indépendant de l'emplacement de la mémoire.
À ce point, rappelons que l'architecture x86 a effectivement un moyen de plus pour fournir un opérande de l' call
enseignement. Il est de la fourniture de l'adresse cible dans un registre. Et une chose très importante à propos de ce format est qu'il est normalement plus rapide que les deux ci-dessus. Qu'est-ce que cela signifie pour nous? Cela signifie qu'une bonne optimisation du compilateur doit et va tirer parti de ce fait. Afin de mettre en œuvre le cycle ci-dessus, le compilateur va essayer d'utiliser un appel par l'intermédiaire d'un registre dans les deux cas. Si elle réussit, la version finale du code peut se présenter comme suit
// Direct call
mov eax, 0x12345678
do-it-many-times
call eax
// Indirect call
mov eax, dword ptr [0x67890ABC]
do-it-many-times
call eax
Remarque, maintenant que la partie questions - de l'appel du cycle corps est exactement la même dans les deux cas. Inutile de dire que la performance va être pratiquement identiques.
On pourrait même dire, aussi étrange que cela puisse paraître, que sur cette plate-forme un appel direct (un appel avec un opérande immédiat en call
) est plus lent qu'un appel indirect, tant que l'opérande de l'appel indirect est fourni dans un registre (plutôt que d'être stockés dans la mémoire).
Bien sûr, la chose n'est pas aussi simple dans le cas général. Le compilateur doit faire face à la disponibilité limitée des registres, de l'aliasing etc. Mais une telle simpliste cas comme dans votre exemple (et même beaucoup plus complexes) ci-dessus d'optimisation sera effectuée par un bon compilateur et d'éliminer complètement la différence de performances entre une reprise cyclique de l'appel direct et une reprise cyclique de l'appel indirect. Cette optimisation fonctionne particulièrement bien en C++, lors de l'appel d'une fonction virtuelle, depuis typiques de la mise en œuvre les pointeurs sont entièrement contrôlés par le compilateur, lui donnant la pleine connaissance de l'aliasing image et d'autres trucs.
Bien sûr, il y a toujours une question de savoir si votre compilateur est assez intelligent pour optimiser les choses comme ça...