53 votes

Le pointeur de fonction ralentit-il le programme?

J'ai lu sur des pointeurs de fonction en C. Et tout le monde dit que va faire mon programme de courir lentement. Est-il vrai?

J'ai fait un programme pour le vérifier. Et j'ai obtenu les mêmes résultats sur les deux cas. (mesure du temps).

Donc, est-ce mauvais pour l'utilisation de pointeur de fonction? Merci à l'avance.

De réponse pour certains gars. J'ai dit "ralentit" pour le moment, que j'ai comparé sur une boucle. comme ceci:

int end = 1000;
int i = 0;

while (i < end) {
 fp = func;
 fp ();
}

Lorsque vous l'exécutez, j'ai eu le même temps, si je l'exécuter.

while (i < end) {
 func ();
}

Donc, je pense que le pointeur de la fonction n'ai pas de différence de temps et ce n'est pas l'exécution d'un programme lent que beaucoup de gens ont dit.

83voto

AndreyT Points 139512

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...

25voto

Tyler McHenry Points 35551

Je pense que quand les gens disent ce qu'ils sont en évoquant le fait que l'utilisation de pointeurs de fonction peut empêcher les optimisations du compilateur (inlining) et le processeur optimisations (direction de la prévision). Toutefois, si des pointeurs de fonction sont un moyen efficace pour accomplir quelque chose que vous êtes en train de faire, les chances sont que de toute autre méthode de faire, il aurait les mêmes inconvénients.

Et à moins que votre pointeurs de fonction sont utilisés dans les boucles serrées dans une critique pour les performances de l'application ou sur un très lente, système embarqué, les chances sont que la différence est négligeable, de toute façon.

9voto

Beanz Points 1088

Beaucoup de gens ont mis dans quelques bonnes réponses, mais je pense qu'il y a un point d'être raté. Pointeurs de fonction ne ajouter un supplément de déréférencement qui les rend plusieurs cycles plus lent, ce nombre peut augmenter à cause d'une mauvaise direction de la prévision (qui, incidemment, n'a presque rien à voir avec le pointeur de la fonction elle-même). En outre, les fonctions appelées par l'intermédiaire d'un pointeur ne peut pas être insérée. Mais ce que les gens sont en manque, c'est que la plupart des gens utilisent des pointeurs de fonction comme une optimisation.

L'endroit le plus commun, vous trouverez des pointeurs de fonction en c/c++ Api est que les fonctions de rappel. La raison pour laquelle tant de nombreux Api ne c'est parce que l'écriture d'un système qui appelle un pointeur de fonction chaque fois que se produisent des événements est beaucoup plus efficace que d'autres méthodes comme la transmission de message. Personnellement, j'ai aussi utilisé des pointeurs de fonction dans le cadre d'un complexe de traitement d'entrée du système, où chaque touche sur le clavier dispose d'un pointeur de fonction mappées à elle par l'intermédiaire d'une table de saut. Cela m'a permis de supprimer toute ramification ou de la logique du système d'entrée et se contente de gérer les clés de la presse à venir dans.

8voto

Péter Török Points 72981

L'appel d'une fonction par l'intermédiaire d'un pointeur de fonction est un peu plus lent que l'appel à une fonction statique, puisque le premier appel comprend un supplément de déréférencement du pointeur. Mais autant que je sache, cette différence est négligeable sur la plupart des machines modernes (sauf peut-être certains des plates-formes spéciales avec des ressources très limitées).

Pointeurs de fonction sont utilisés, car ils peuvent rendre le programme encore plus simple, plus propre et plus facile à maintenir (lorsqu'il est utilisé correctement, bien sûr). Cela fait plus de place pour le possible très mineur différence de vitesse.

7voto

Yacoby Points 29771

À l'aide d'un pointeur de fonction est plus lent que juste l'appel d'une fonction, telle qu'elle est, une autre couche d'indirection. (Le pointeur doit être déréférencé pour obtenir l'adresse mémoire de la fonction). Alors qu'il est plus lent, par rapport à tout le reste de votre programme peut faire (Lecture d'un fichier, écrire dans la console) il est négligeable.

Si vous avez besoin d'utiliser des pointeurs de fonction, de les utiliser, car tout ce qui tente de faire la même chose, mais évite de les utiliser sera plus lent et moins facile à gérer que l'utilisation des pointeurs de fonction.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X