Comment faire des pointeurs de fonction en C travail?
J'ai eu une certaine expérience de ces derniers temps avec des pointeurs de fonction en C.
Afin de poursuivre la tradition de répondre à vos propres questions, j'ai décidé de faire un petit résumé de l'essentiel, pour ceux qui ont besoin d'une petite plongée dans le sujet.
Aussi: Pour un peu d'une analyse en profondeur de C les pointeurs, voir blogs.oracle.com/ksplice/entry/the_ksplice_pointer_challenge. Aussi, la Programmation à partir de la base montre comment ils travaillent sur le niveau de la machine. La compréhension de C "modèle de mémoire" est très utile pour comprendre comment C les pointeurs de travail.
Grande info. Par le titre même si, je m'attendais à vraiment voir une explication de la façon dont les "pointeurs de fonction de travail", pas de la façon dont ils sont codés 🙂
"Comment faire des pointeurs de fonction en C travail?" Très bien, merci.
Grande info. Par le titre même si, je m'attendais à vraiment voir une explication de la façon dont les "pointeurs de fonction de travail", pas de la façon dont ils sont codés 🙂
"Comment faire des pointeurs de fonction en C travail?" Très bien, merci.
OriginalL'auteur |
Vous devez vous connecter pour publier un commentaire.
Pointeurs de fonction en C
Commençons avec une fonction de base qui nous sera pointant vers:
Première chose, nous allons définir un pointeur vers une fonction qui reçoit 2
int
s et renvoie unint
:Maintenant nous pouvons point à notre fonction:
Maintenant que nous avons un pointeur vers la fonction, nous allons utiliser:
En passant le pointeur à une autre fonction est fondamentalement la même:
Nous pouvons utiliser des pointeurs de fonction dans les valeurs de retour ainsi (essayer de suivre, il obtient le désordre):
Mais il est beaucoup plus agréable d'utiliser un
typedef
:"functionPtr = &addInt;" peut aussi être écrit (et est souvent) comme " functionPtr = addInt;" qui est également valable étant donné que la norme dit que le nom d'une fonction dans ce contexte est converti à l'adresse de la fonction.
hlovdal, dans ce contexte, il est intéressant d'expliquer que c'est ce qui permet d'écrire functionPtr = ******************addInt;
Je sais que c'est 4 ans trop tard, mais je suppose que d'autres personnes pourraient bénéficier de cette: des pointeurs de Fonction sont utiles pour le passage de fonctions en tant que paramètres à d'autres fonctions. Il a fallu beaucoup de recherche pour moi de trouver cette réponse pour une raison étrange. Donc, fondamentalement, il donne à la C pseudo de première classe de la fonctionnalité.
pointeurs de fonction sont agréables pour l'exécution du PROCESSEUR de détection. Plusieurs versions de certaines fonctions pour profiter de l'ESS, popcnt, AVX, etc. Au démarrage, définissez vos pointeurs de fonction à la meilleure version de chaque fonction pour le CPU actuel. Dans votre code, il suffit d'appeler via le pointeur de fonction au lieu d'avoir des branches conditionnelles sur les fonctions du PROCESSEUR partout. Ensuite, vous pouvez faire compliqué logique de décider que, même si ce CPU prend en charge
pshufb
, c'est lent, donc, plus tôt la mise en œuvre est encore plus rapide. x264/x265 utiliser cette profondeur, et sont open source.OriginalL'auteur Yuval Adam
Pointeurs de fonction en C peut être utilisé pour effectuer la programmation orientée objet en C.
Par exemple, les lignes suivantes est écrit en C:
Oui, le
->
et l'absence d'unnew
opérateur est morte donner, mais il est certain que semble sous-entendre que nous sommes définir le texte de certainsString
de la classe"hello"
.En utilisant des pointeurs de fonction, il est possible d'émuler des méthodes en C.
Comment est-ce que c'est possible?
La
String
classe est en fait unestruct
avec un tas de pointeurs de fonctions qui agissent comme un moyen de simuler des méthodes. Ce qui suit est une déclaration partielle de laString
classe:Comme on peut le voir, les méthodes de la
String
de classe sont en fait des pointeurs de fonction à la fonction déclarée. Dans la préparation de l'exemple de laString
, lenewString
fonction est appelée afin de mettre en place les pointeurs de fonction à leurs fonctions respectives:Par exemple, la
getString
fonction qui est appelée par l'invocation de laget
méthode est définie comme suit:Une chose qui peut être remarqué, c'est qu'il n'y a pas de concept d'une instance d'un objet et avoir des méthodes qui sont en fait une partie d'un objet, donc une "auto objet" doit être transmise à chaque invocation. (Et le
internal
est juste cachéstruct
qui a été omis de la liste de code plus tôt, c'est une façon de procéder se cacher de l'information, mais qui ne sont pas pertinents à des pointeurs de fonction.)Donc, plutôt que d'être capable de faire
s1->set("hello");
, il faut passer dans l'objet pour effectuer l'action surs1->set(s1, "hello")
.Avec des mineurs de l'explication d'avoir à passer une référence à vous-même hors de la voie, nous allons passer à la partie suivante, qui est l'héritage en C.
Disons que nous voulons faire une sous-classe de
String
, dire unImmutableString
. Afin de rendre la chaîne immuable, laset
méthode ne sera pas accessible, tout en conservant l'accès àget
etlength
, et force le "constructeur" à accepter unchar*
:Fondamentalement, pour toutes les classes, les méthodes disponibles sont une fois de plus des pointeurs de fonction. Cette fois, la déclaration pour la
set
méthode n'est pas présent, il ne peut donc pas être appelé dans uneImmutableString
.Que pour la mise en œuvre de la
ImmutableString
, le seul code est le "constructeur" de la fonction, lanewImmutableString
:Dans l'instanciation de la
ImmutableString
, les pointeurs de fonction à laget
etlength
méthodes de référence pour laString.get
etString.length
méthode, en passant par labase
variable qui est stockée en interneString
objet.L'utilisation d'un pointeur de fonction peut atteindre l'héritage d'une méthode à partir d'une superclasse.
Nous ne pouvons plus continuer à polymorphisme en C.
Par exemple, si nous voulions changer le comportement de la
length
méthode pour retourner0
tout le temps dans leImmutableString
classe pour une raison quelconque, tout ce qui devrait être fait est de:length
méthode.length
méthode.L'ajout d'une grande
length
méthode dansImmutableString
peut être effectuée par l'ajout d'unlengthOverrideMethod
:Ensuite, le pointeur de fonction pour le
length
méthode dans le constructeur est accroché jusqu'à lalengthOverrideMethod
:Maintenant, plutôt que d'avoir un comportement identique pour les
length
méthode dansImmutableString
classe que leString
classe, maintenant lalength
méthode se réfèrent au comportement défini dans lelengthOverrideMethod
fonction.Je dois ajouter un avertissement que je suis en train d'apprendre à écrire avec un orientée objet, le style de programmation en C, donc il y a sans doute des points que je n'ai pas bien expliquer, ou peut-être juste hors de la marque en termes de la façon dont mieux pour mettre en œuvre la programmation orientée objet en C. Mais mon but était de tenter d'illustrer l'une des nombreuses utilisations de pointeurs de fonction.
Pour plus d'informations sur la façon d'effectuer la programmation orientée objet en C, veuillez consulter les questions suivantes:
C'est OO tout droit, mais pas n'importe où près de la C-style OO. Ce que vous avez brokenly mis en œuvre est le Javascript de style basé sur des prototypes OO. Pour obtenir C++/Pascal-style OO, vous devez: 1. Avoir un const struct pour une table virtuelle de chaque de la classe avec des membres virtuels. 2. Ont pointeur vers cette structure polymorphe objets. 3. Appel de méthodes virtuelles via la table virtuelle, et toutes les autres méthodes directement -- généralement de s'en tenir à certains
ClassName_methodName
fonction de convention de nommage. Alors seulement, vous bénéficiez du même moteur d'exécution et les coûts de stockage que vous le faire en C++ et Pascal.Travail OO avec une langue qui n'est pas destiné à être OO est toujours une mauvaise idée. Si vous voulez OO et encore C juste de travailler avec C++.
Dire que les développeurs du noyau Linux. "toujours une mauvaise idée" est strictement votre avis, avec qui je suis fermement en désaccord.
J'aime cette réponse, mais on ne jette pas de malloc
OriginalL'auteur
Le guide de licenciement: Comment l'abus des pointeurs de fonction dans GCC sur des machines x86 par la compilation de votre code à la main:
Ces littéraux de chaîne sont des octets de 32 bits x86 code machine.
0xC3
est un x86ret
enseignement.Vous ne serait pas l'habitude d'écrire à la main, vous voulez écrire en langage d'assemblage et ensuite utiliser un assembleur comme
nasm
de le monter dans un plat binaire qui vous convertir en un C un littéral de chaîne.Retourne la valeur courante du registre EAX
Écrire une fonction d'échange de
Écrire un compteur de boucle de 1000, en appelant une fonction à chaque fois
Vous pouvez même écrire une fonction récursive qui compte pour 100
Noter que les compilateurs place littéraux de chaîne dans la
.rodata
section (ou.rdata
sur Windows), qui est liée dans le cadre du segment de texte (avec code pour les fonctions).Le segment de texte a Lire+Exec autorisation, afin de casting littéraux de chaîne de pointeurs de fonction fonctionne sans avoir besoin
mprotect()
ouVirtualProtect()
appels système comme vous auriez besoin pour la mémoire allouée dynamiquement. (Ougcc -z execstack
liens du programme avec pile + segment de données + tas exécutable, comme un rapide hack.)À démonter ces, vous pouvez le compiler à mettre une étiquette sur les octets, et utiliser un désassembleur.
De la compilation avec
gcc -c -m32 foo.c
et à démonter avecobjdump -D -rwC -Mintel
, nous pouvons obtenir de l'assemblée, et que ce code viole les ABI casser les EBX (un appel préservé registre) et est généralement inefficace.Ce code machine sera (probablement) de travail dans le code 32 bits sur Windows, Linux, OS X, et ainsi de suite: par défaut, les conventions d'appel sur tous les Systèmes d'exploitation passer des arguments sur la pile au lieu de manière plus efficace dans les registres. Mais EBX est conservé dans toutes les conventions d'appel, afin de l'utiliser comme une égratignure registre sans sauvegarde/restauration de on peut facilement faire de l'appelant incident.
Salut Matt! Selon le niveau d'optimisation, GCC souvent inline constantes de chaîne dans le segment de TEXTE, ce qui permettra de travailler encore sur une version plus récente de windows à condition de ne pas interdire ce type d'optimisation. (IIRC, la version MINGW au moment de mon post de plus de deux ans inlines littéraux de chaîne par défaut sur le niveau d'optimisation)
quelqu'un pourrait-il expliquer ce qui se passe ici? Quels sont ces étranges à la recherche des littéraux de chaîne?
On dirait qu'il est écrit premières valeurs hexadécimales (par exemple '\x00' est la même que '/0', ils sont tous les deux égaux à 0) dans une chaîne, puis la coulée de la chaîne en C pointeur de fonction, puis l'exécution de la fonction C pointeur parce qu'il est le diable.
salut FUZxxl, je pense qu'il pourrait varier en fonction du compilateur et de la version du système d'exploitation. Le code ci-dessus semble fonctionner correctement sur codepad.org; codepad.org/FMSDQ3ME
OriginalL'auteur
L'un de mes préférés utilise pour les pointeurs de fonction est aussi bon marché et facile itérateurs -
D'accord. Tous mes itérateurs ressembler à ceci:
int (*cb)(void *arg, ...)
. La valeur de retour de l'itérateur permet aussi de m'arrêter plus tôt (si différente de zéro).OriginalL'auteur
Pointeurs de fonction facile à déclarer une fois que vous avez la base declarators:
ID
: ID est un*D
: D pointeur versD(<parameters>)
: D fonction prenant<
paramètres>
retourAlors que D est une autre déclaration construit à l'aide de ces mêmes règles. En fin de compte, quelque part, elle se termine avec
ID
(voir ci-dessous pour un exemple), qui est le nom de la déclaration de l'entité. Nous allons essayer de construire une fonction prenant un pointeur vers une fonction prend rien et le retour de type int, et retournant un pointeur à une fonction prenant un char et le retour de type int. Avec type-defs c'est comme çaComme vous le voyez, il est assez facile de le construire à l'aide de typedefs. Sans typedefs, il n'est pas difficile, soit avec la déclaration de règles, appliquées de manière cohérente. Comme vous le voyez j'ai raté la partie sur laquelle pointe le pointeur, et la chose la fonction retourne. C'est ce qui apparaît à l'extrême gauche de la déclaration, et n'est pas d'intérêt: Il est ajouté à la fin si l'on construit le constate déjà. Faisons-le. Mettre en place de manière cohérente, premier long - montrant la structure à l'aide de
[
et]
:Comme vous le voyez, on peut décrire un type complètement en ajoutant declarators l'une après l'autre. La Construction peut se faire de deux façons. On est bottom-up, à commencer par la très bonne chose (les feuilles) et sur le même chemin jusqu'à l'identificateur. L'autre façon est de haut en bas, en commençant à l'identifiant, le travail de la manière vers le bas pour les feuilles. Je vais vous montrer deux façons.
De Bas En Haut
La Construction commence par la chose à la droite: La chose retourné, ce qui est la fonction la prise de char. Pour garder la declarators distinctes, je vais les numéroter:
Inséré le char paramètre directement, puisqu'il est trivial. L'ajout d'un pointeur de déclaration par le remplacement de
D1
par*D2
. Notez que nous avons pour envelopper les parenthèses autour de*D2
. Ce qui peut être connu par la recherche de la primauté de la*-operator
et la fonction d'appel de l'opérateur()
. Sans notre parenthèses, le compilateur pourrait le lire comme*(D2(char p))
. Mais ce ne serait pas un simple remplacement de D1 par*D2
plus, bien sûr. Les parenthèses sont toujours autorisés autour de declarators. Afin de ne pas faire quelque chose de mal si vous ajoutez trop d'entre eux, en fait.Type de retour est complet! Maintenant, nous allons remplacer
D2
par la fonction de demande de déclaration fonction prenant<parameters>
retour, qui estD3(<parameters>)
laquelle nous sommes maintenant.Notez que les parenthèses sont nécessaires, car nous voulez
D3
à une fonction de demande de déclaration et non pas un pointeur déclaration de ce temps. La grande, la seule chose qui reste est les paramètres pour cela. Le paramètre est en fait exactement la même chose que nous avons fait le type de retour, juste avecchar
remplacé parvoid
. Donc je vais le copier:J'ai remplacé
D2
parID1
, puisque nous en avons terminé avec ce paramètre (c'est déjà un pointeur vers une fonction - pas besoin d'une autre demande de déclaration).ID1
sera le nom du paramètre. Maintenant, j'ai dit ci-dessus à la fin on ajoute le type qui tous ceux déclaration de modifier, l'une apparaissant à l'extrême gauche de chaque déclaration. Pour les fonctions, qui devient le type de retour. Pour les pointeurs le fait de taper etc... C'est intéressant lorsqu'il est écrit en bas de la type, il apparaîtra dans l'ordre inverse, à droite 🙂 de toute façon, en le substituant les rendements de la déclaration complète. Les deux foisint
de cours.J'ai appelé l'identificateur de la fonction
ID0
dans cet exemple.De Haut En Bas
Cela commence à l'identifiant le plus à gauche dans la description du type, de l'emballage, qui constate que nous marchons notre chemin à travers le droit. Commencez avec fonction prenant
<
paramètres>
retourLa prochaine chose dans la description (d'après "le retour") a été pointeur vers. Nous allons l'intégrer:
Puis la prochaine chose était due à la prise de
<
paramètres>
retour. Le paramètre est un simple char, afin de nous mettre tout de suite à nouveau, car il est vraiment trivial.Notez les parenthèses, nous avons ajouté, depuis que nous voulons plus que le
*
se lie d'abord, et puis la(char)
. Sinon, il serait de lire fonction prenant<
paramètres>
le retour de fonction .... Rex, fonctions retournant des fonctions qui ne sont même pas autorisés.Maintenant nous avons juste besoin de mettre
<
paramètres>
. Je vais vous montrer une version courte de la deriveration, car je pense que vous avez déjà maintenant avoir l'idée de comment le faire.Vient de mettre
int
avant la declarators comme nous l'avons fait avec bottom-up, et nous sommes finisLa bonne chose
Est bottom-up ou top-down de mieux? J'ai l'habitude de bottom-up, mais certaines personnes peuvent être plus à l'aise avec de haut en bas. C'est une question de goût je pense. D'ailleurs, si vous appliquez tous les opérateurs dans cette déclaration, vous finirez toujours par un int:
Qui est un bel établissement de déclarations en C: La déclaration affirme que si ces opérateurs sont utilisés dans une expression à l'aide de l'identifiant, puis il donne le type de la plus à gauche. C'est comme ça pour les tableaux de trop.
Espère que vous avez aimé ce petit tutoriel! Maintenant, nous pouvons lien vers cette quand les gens s'interroger sur l'étrange syntaxe de déclaration de fonctions. J'ai essayé de mettre un peu de C internals que possible. N'hésitez pas à modifier/corriger les choses.
OriginalL'auteur
Une autre bonne utilisation de pointeurs de fonction:
la Commutation entre les versions sans douleur
Ils sont très pratique à utiliser lorsque vous souhaitez des fonctions différentes à des moments différents, ou des différentes phases de développement. Par exemple, je suis du développement d'une application sur un ordinateur hôte qui a une console, mais la version finale du logiciel sera mis sur un Avnet ZedBoard (qui a des ports pour les écrans et consoles, mais ils ne sont pas nécessaires/voulu pour la version finale). Donc, au cours du développement, je vais utiliser
printf
d'affichage de l'état et des messages d'erreur, mais quand je suis fait, je ne veux pas que tout ce qui est imprimé. Voici ce que j'ai fait:version.h
Dans
version.c
je vais définir les 2 prototypes de fonction présente dansversion.h
version.c
Remarquez comment le pointeur de fonction est prototypée dans
version.h
commevoid (* zprintf)(const char *, ...);
Lorsqu'il est référencé dans l'application, il va commencer à exécuter partout où il est pointé, qui doit encore être défini.
Dans
version.c
, avis dans laboard_init()
fonction oùzprintf
est affecté à une fonction unique (dont la fonction de signature matches), selon la version qui est définie dansversion.h
zprintf = &printf;
zprintf appels printf à des fins de débogageou
zprintf = &noprint;
zprintf retourne juste et ne pas exécuter de code inutileD'exécuter le code ressemblera à ceci:
mainProg.c
Le code ci-dessus va utiliser
printf
si en mode de débogage, ou ne rien faire si en mode release. C'est beaucoup plus facile que de passer par l'ensemble du projet et de la commenter ou la suppression de code. Tout ce que je dois faire est de changer la version dansversion.h
et le code fera le reste!OriginalL'auteur
Pointeur de fonction est généralement défini par typedef, et utilisé comme param & valeur de retour,
Réponses ci-dessus déjà expliqué beaucoup de choses, je viens de donner un exemple complet:
OriginalL'auteur
L'une des grandes utilisations pour les pointeurs de fonction en C, c'est d'appeler une fonction sélectionnée au moment de l'exécution. Par exemple, la bibliothèque run-time C a deux routines,
qsort
etbrecherche
, qui prend un pointeur vers une fonction qui est appelée à comparer deux éléments en cours de tri; cela vous permet de tri ou de recherche, respectivement, n'importe quoi, sur la base des critères que vous souhaitez utiliser.Un exemple très simple, si il y a une fonction appelée
print(int x, int y)
qui à son tour peut exiger pour appeler une fonction (add()
ousub()
, qui sont du même type), alors ce que nous allons faire, nous allons ajouter un pointeur de fonction en argument à laprint()
fonction comme indiqué ci-dessous:La sortie est:
OriginalL'auteur
Un pointeur de fonction est une variable qui contient l'adresse d'une fonction. Depuis, il est un pointeur de variable mais avec quelques restreint de propriétés, vous pouvez l'utiliser un peu comme vous le feriez pour tout autre pointeur de variable dans la structure des données.
La seule exception est, je pense, le traitement de la fonction pointeur pointant vers autre chose qu'une valeur unique. Faire de l'arithmétique des pointeurs par incrémentation ou la décrémentation d'un pointeur de fonction ou en ajoutant ou en supprimant un décalage d'un pointeur de fonction n'est pas vraiment d'aucune utilité comme un pointeur de fonction des points que pour une seule chose, le point d'entrée d'une fonction.
De la taille d'un pointeur de fonction variable, le nombre d'octets occupés par la variable, peut varier en fonction de l'architecture sous-jacente, par exemple x32 ou x64 ou quoi que ce soit.
La déclaration d'un pointeur de fonction variable doit spécifier le même genre d'information que d'une déclaration de fonction pour que le compilateur C de faire les types de contrôles qu'il le fait normalement. Si vous ne spécifiez pas une liste de paramètres dans la déclaration/définition du pointeur de fonction, le compilateur C ne sera pas en mesure de vérifier l'utilisation de paramètres. Il ya des cas où cette absence de vérification peut être utile, cependant, rappelez-vous qu'un filet de sécurité a été supprimé.
Quelques exemples:
Les deux premiers declararations sont un peu similaire:
func
est une fonction qui prend unint
et unchar *
et renvoie unint
pFunc
est un pointeur de fonction à laquelle est attribuée l'adresse d'une fonction qui prend unint
et unchar *
et renvoie unint
Donc, à partir de ce qui précède, nous pourrions avoir une ligne de source, dans lequel l'adresse de la fonction
func()
est affecté à la fonction pointeur de variablepFunc
comme danspFunc = func;
.Notez la syntaxe utilisée avec un pointeur de fonction déclaration/définition dans laquelle les parenthèses sont utilisées pour surmonter le naturel de règles de priorité des opérateurs.
Plusieurs Exemples D'Utilisation
Quelques exemples de l'utilisation d'un pointeur de fonction:
Vous pouvez utiliser la variable longueur des listes de paramètres dans la définition d'un pointeur de fonction.
Ou vous ne pouvez pas spécifier une liste de paramètres. Cela peut être utile, mais il élimine la possibilité pour le compilateur C pour effectuer des contrôles sur la liste d'arguments fournis.
C style Jette
Vous pouvez utiliser C style jette avec des pointeurs de fonction. Cependant, soyez conscient qu'un compilateur C peut être laxistes concernant les contrôles ou de fournir des avertissements plutôt que des erreurs.
Comparer Pointeur de Fonction à l'Égalité
Vous pouvez vérifier qu'un pointeur de fonction est égale à une fonction particulière de l'adresse à l'aide d'un
if
déclaration si je ne suis pas sûr de l'utilité que pourrait l'être. D'autres opérateurs de comparaison semble avoir encore moins d'utilité.Un Tableau de Pointeurs de Fonction
Et si vous voulez avoir un tableau de pointeurs de fonction de chacun des éléments de la liste d'arguments a des différences, alors vous pouvez définir un pointeur de fonction avec la liste des arguments non spécifié (pas
void
ce qui signifie pas d'arguments mais juste non spécifiée) quelque chose comme ce qui suit si vous pouvez voir des avertissements du compilateur C. Cela fonctionne aussi pour un pointeur de fonction paramètre à une fonction:C style
namespace
l'Aide de Globalstruct
avec des Pointeurs de FonctionVous pouvez utiliser le
static
mot-clé pour spécifier une fonction dont le nom est portée sur le fichier, puis assigner à une variable globale comme un moyen de fournir quelque chose de similaire à lanamespace
fonctionnalités de C++.Dans un fichier d'en-tête de définir une structure qui sera notre espace de noms avec une variable globale qui l'utilise.
Puis dans le fichier source C:
Ce serait alors utilisé en indiquant le nom complet de struct global variable et le nom du membre pour accéder à la fonction. Le
const
modificateur est utilisé sur le monde de sorte qu'il ne peut pas être changé par accident.Domaines d'Application de Pointeurs de Fonction
Une bibliothèque DLL composant pourrait faire la même chose pour le style C
namespace
approche dans laquelle un particulier à l'interface de la bibliothèque est demandé à partir d'une méthode de fabrique dans une bibliothèque d'interface qui prend en charge la création d'unstruct
contenant des pointeurs de fonction.. Cette interface de la bibliothèque des charges de la demande de version de la DLL, crée une structure avec le nécessaire pointeurs de fonction, et retourne ensuite la structure de la demande de l'appelant pour les utiliser.et il pourrait être utilisé comme:
La même approche peut être utilisée pour définir un résumé du matériel de la couche de code qui utilise un modèle particulier du matériel sous-jacent. Pointeurs de fonction sont remplis avec du matériel spécifique de fonctions par une usine pour fournir le matériel des fonctionnalités spécifiques qui implémente les fonctions précisées dans l'abstrait sur le modèle de matériel. Ceci peut être utilisé pour fournir un résumé couche du matériel utilisé par le logiciel, qui appelle une fonction de fabrication afin d'obtenir le matériel spécifique à la fonction d'interface, puis utilise les pointeurs de fonction fourni pour effectuer des actions pour le matériel sous-jacent, sans avoir besoin de connaître les détails de l'application sur la cible spécifique.
Pointeurs de fonction pour créer les Délégués, les Gestionnaires et les Rappels
Vous pouvez utiliser des pointeurs de fonction comme un moyen de déléguer certaines tâches ou des fonctions. L'exemple classique en C est la comparaison de la fonction de délégué du pointeur utilisé avec la Norme de fonctions de la bibliothèque C
qsort()
etbsearch()
de fournir le classement de l'ordre de tri d'une liste d'éléments ou d'effectuer une recherche binaire sur une liste triée des éléments. La comparaison de la fonction de délégué indique le classement de l'algorithme utilisé dans le tri ou le binaire de recherche.Une autre utilisation est similaire à l'application d'un algorithme pour le C++ Standard Template Library conteneur.
Est un autre exemple avec la GUI code source, dans lequel un gestionnaire pour un événement particulier est inscrit en fournissant un pointeur de fonction qui est en fait appelée lorsque l'événement se produit. Microsoft MFC-cadre avec son message de cartes utilise quelque chose de semblable à gérer les messages sont livrés à une fenêtre ou d'un fil.
Asynchrone fonctions qui nécessitent un rappel sont similaires à un gestionnaire d'événement. L'utilisateur de l'asynchrone appels de fonction les fonctions asynchrones pour commencer un peu d'action et fournit un pointeur de fonction qui asynchrone fonction d'appel une fois que l'action est terminée. Dans ce cas, l'événement est asynchrone fonction de l'achèvement de sa tâche.
OriginalL'auteur
À partir de zéro de la fonction de la Mémoire de l'Adresse De l'endroit Où Ils commencent à exécuter. En Langage d'Assemblage, Ils Sont appelé (appel "de la fonction de l'adresse de mémoire").Maintenant de revenir à C Si la fonction a une adresse en mémoire, puis ils peuvent être manipulés par des Pointeurs en C. Donc, Par les règles de C
1.Vous devez d'abord déclarer un pointeur de fonction
2.Passer l'Adresse de la fonction Désirée
****Note->les fonctions doivent être de même type****
Ce Simple Programme permettra d'Illustrer Chaque Chose.
Après Qui vous permet de Voir Comment la machine Comprend.Aperçu de la machine instruction du programme ci-dessus en architecture 32 bits.
De la marque rouge de la zone est de montrer comment l'adresse échange et le stockage dans eax.Ensuite, leur est un appel à l'instruction sur l'eax. eax contient l'adresse de votre choix de la fonction
OriginalL'auteur
Depuis des pointeurs de fonction sont souvent tapé rappels, vous pouvez avoir un coup d'oeil à type de coffre-fort rappels. La même chose s'applique aux points d'entrée, etc de fonctions qui ne sont pas des rappels.
C est assez volage et de pardonner en même temps 🙂
OriginalL'auteur