Wie Funktionszeigern in C arbeiten?
Hatte ich einige Erfahrungen in letzter Zeit mit Funktionszeigern in C
So vor sich geht mit der tradition der Beantwortung Ihrer eigenen Fragen, die ich beschlossen, eine kleine Zusammenfassung der Grundlagen, für diejenigen, die brauchen ein schnelles abtauchen in das Thema.
Auch: ein bisschen ein in-depth-Analyse von C-Zeigern finden Sie unter blogs.oracle.com/ksplice/entry/the_ksplice_pointer_challenge. Auch, Programmierung aus dem Boden nach Oben zeigt, wie Sie an der Maschine arbeiten Ebene. Verständnis C "- Speicher-Modell" ist sehr nützlich für das Verständnis von C-Zeigern arbeiten.
Tolle info. Durch den Titel, obwohl ich erwartet hätte, wirklich zu sehen, eine Erklärung, wie "Funktionszeigern arbeiten", nicht, wie Sie kodiert sind 🙂
"Wie Funktionszeigern in C arbeiten?" Gut, danke.
Tolle info. Durch den Titel, obwohl ich erwartet hätte, wirklich zu sehen, eine Erklärung, wie "Funktionszeigern arbeiten", nicht, wie Sie kodiert sind 🙂
"Wie Funktionszeigern in C arbeiten?" Gut, danke.
InformationsquelleAutor |
Du musst angemeldet sein, um einen Kommentar abzugeben.
Funktionszeigern in C
Beginnen wir mit einem basic-Funktion, die wir Hinweis auf:
Erstes definieren wir einen Zeiger auf eine Funktion, die Sie erhält: 2
int
s und gibt eineint
:Nun können wir sicher auf unserer Funktion:
Nun haben wir einen Zeiger auf die Funktion, lasst uns es verwenden:
Übergeben Sie den Zeiger auf eine andere Funktion ist im Grunde das gleiche:
Können wir die Verwendung von Funktionszeigern in return-Werte als auch (versuchen zu halten, wird es unordentlich):
Aber es ist viel schöner zu verwenden, eine
typedef
:"functionPtr = &addInt;" kann auch geschrieben werden (und oft ist) als " functionPtr = addInt;" das ist auch gültig, da der standard sagt, dass eine Funktion den Namen in diesem Zusammenhang wird umgewandelt in die Adresse der Funktion.
hlovdal, in diesem Zusammenhang ist es interessant zu erklären, dass dies ist, was kann man schreiben functionPtr = ******************addInt;
Ich weiß, das ist 4 Jahre zu spät, aber ich glaube, andere Menschen könnten davon profitieren: Funktion Zeiger sind nützlich für die übergabe von Funktionen als Parameter an andere Funktionen. Es dauerte eine Menge des Suchens für mich zu finden, die Antwort für einige ungerade Grund. Also im Grunde gibt es C pseudo-first-class-Funktionalität.
Funktionszeiger sind schön für die Erkennung der CPU zur Laufzeit. Mehrere Versionen einige Funktionen zu nutzen, SSE, popcnt, AVX, etc. Beim Start, stellen Sie Ihre Funktion ein Zeiger auf die beste version, die jeder Funktion, die für die aktuelle CPU. In deinem anderen code haben, rufen Sie einfach durch die Funktion Zeiger statt mit bedingten Verzweigungen auf die CPU-Funktionen überall. Dann können Sie tun, komplizierte Logik über die Entscheidung, dass, obwohl diese CPU unterstützt
pshufb
, es ist langsam, so dass die frühere Anwendung ist immer noch schneller. x264/x265 verwenden Sie diese ausgiebig, und sind open source.InformationsquelleAutor Yuval Adam
Funktionszeigern in C kann verwendet werden, um Objekt-orientierte Programmierung in C.
Beispielsweise die folgenden Zeilen, ist in C geschrieben:
Ja, die
->
und das fehlen einernew
Betreiber ist eine tote geben Weg, aber es sicher scheint zu implizieren, dass wir die Einstellung der text von einigenString
Klasse"hello"
.Durch die Verwendung von Funktionszeigern, es möglich ist, zu emulieren Methoden in C.
Wie wird dies erreicht?
Den
String
Klasse ist eigentlich einestruct
mit einer Reihe von Funktionszeigern, welche eine Möglichkeit zum simulieren von Methoden. Das folgende ist eine unvollständige Erklärung derString
Klasse:Wie gesehen werden kann, sind die Methoden, die
String
Klasse sind eigentlich Funktion Zeiger auf den deklarierten Funktion. In Vorbereitung der Instanz derString
, dienewString
Funktion wird aufgerufen, um die Funktion Zeiger auf Ihren jeweiligen Funktionen:Beispielsweise die
getString
Funktion, die aufgerufen wird, aufrufen derget
Methode ist wie folgt definiert:Eine Sache, die bemerkt werden kann, ist, dass es kein Konzept für eine Instanz eines Objekts und Methoden, die eigentlich ein Teil eines Objekts, also ein "selbst-Objekt" übergeben werden muss in jedem Aufruf. (Und die
internal
ist nur eine verstecktestruct
was weggelassen wurde aus der code-Liste zuvor -- es ist eine Art und Weise der Durchführung information hiding, aber das ist nicht relevant für Funktionszeiger.)Also, anstatt in der Lage zu tun
s1->set("hello");
, man muss sich übergeben, das Objekt zum ausführen der Aktion aufs1->set(s1, "hello")
.Mit, dass kleine Erläuterung zu müssen, übergeben Sie eine Referenz, um sich aus dem Weg, verschieben wir auf den nächsten Teil, der Vererbung in C.
Sagen wir, wir wollen eine Unterklasse von
String
, dass einImmutableString
. Um die string-immutable, dieset
Methode nicht zugänglich, während die Aufrechterhaltung des Zugangs zuget
undlength
, und die Kraft der "Konstruktor" zu akzeptierenchar*
:Grundsätzlich für alle Unterklassen, die verfügbaren Methoden sind wieder einmal Funktionszeiger. Diese Zeit, die Erklärung für die
set
Methode ist nicht vorhanden, es kann daher nicht aufgerufen werden in einemImmutableString
.Als für die Umsetzung der
ImmutableString
, die nur den relevanten code ist der "Konstruktor" - Funktion, dienewImmutableString
:In der Instanziierung des
ImmutableString
die Funktion Zeiger auf dieget
undlength
Methoden beziehen sich eigentlich auf dieString.get
undString.length
Methode, indem Sie durch diebase
variable, die intern gespeichertString
Objekt.Den Einsatz eines funktionszeigers erreichen können, die Vererbung einer Methode aus einer Oberklasse.
Können wir weiter Polymorphismus in C.
Wenn zum Beispiel wollten wir ändern das Verhalten der
length
Methode zurück0
alle Zeit derImmutableString
Klasse aus irgendeinem Grund, das würde alles noch zu erledigen ist:length
Methode.length
Methode.Hinzufügen eines überwiegenden
length
Methode inImmutableString
kann durchgeführt werden, indem einlengthOverrideMethod
:Dann, die Funktion Zeiger für die
length
Methode im Konstruktor ist angeschlossen an daslengthOverrideMethod
:Nun, anstatt ein identisches Verhalten für die
length
Methode inImmutableString
KlasseString
Klasse, jetzt dielength
Methode beziehen sich auf das Verhalten definiert, die in derlengthOverrideMethod
Funktion.Muss ich eine Verzichtserklärung hinzufügen, dass ich bin immer noch lernen, wie zu schreiben, mit einem Objekt-orientierten Programmierstil in C, also wahrscheinlich gibt es Punkte, die ich nicht gut erklären, oder nur aus-Markierung im Sinne der bestmöglichen Umsetzung von OOP in C Aber mein Ziel war zu versuchen, um zu illustrieren, einer von vielen verwendet, von Funktionszeigern.
Weitere Informationen zum durchführen der Objekt-orientierten Programmierung in C, beziehen Sie sich bitte auf die folgenden Fragen:
Dies ist OO alles in Ordnung, aber nicht überall in der Nähe der C-style OO. Was haben Sie brokenly implementierte Javascript-Stil Prototypen-basierte OO. Um C++/Pascal-Stil-OO, müssten Sie: 1. Eine const struct für eine virtuelle Tabelle für jedes Klasse mit virtuellen Mitglieder. 2. Haben Zeiger auf die struct in der polymorphe Objekte. 3. Aufruf der virtuellen Methoden über den virtuellen Tisch, und alle anderen Methoden, die direkt-in der Regel durch kleben, um einige
ClassName_methodName
Funktion naming convention. Erst dann erhalten Sie die gleiche Laufzeit-und Lagerkosten, wie Sie in C++ und Pascal.Arbeiten OO mit einer Sprache, die nicht sein soll OO ist immer eine schlechte Idee. Wenn du willst OO und noch haben C einfach mit C++.
Sagen Sie das den Linux-kernel-Entwickler. "immer eine schlechte Idee" ist streng deine Meinung, mit der ich nachdrücklich widersprechen.
Ich mag diese Antwort, aber nicht gegossen, malloc
InformationsquelleAutor
Den guide, um gefeuert zu werden: Wie, um Missbrauch zu Funktionszeigern in GCC auf x86-Rechner kompilieren Sie Ihren code von hand:
Diese string-Literale sind bytes der 32-bit-x86-Maschinencode.
0xC3
ist ein x86ret
- Anweisung.Würden Sie normalerweise nicht schreiben, dies von hand zu machen, würden Sie schreiben in Assembler und dann verwenden Sie einen assembler, wie
nasm
zur Montage in eine flache binären die Sie hexdump in eine C-string-literal.Gibt den aktuellen Wert auf dem register "EAX"
Schreiben Sie eine swap-Funktion
Schreiben Sie eine for-Schleife Zähler bis 1000, rief einige Funktion jedes mal
Sie können sogar schreiben Sie eine rekursive Funktion, die zählt 100
Beachten Sie, dass Compiler Ort, string-Literale in die
.rodata
Abschnitt (oder.rdata
auf Windows), die verknüpft ist als Teil des text-segment (zusammen mit dem code für Funktionen).Text-segment Gelesen hat+Exec-Berechtigung, so casting-string-Literale zu Funktionszeigern arbeitet ohne
mprotect()
oderVirtualProtect()
system-Aufrufe, wie Sie müssten für dynamisch allozierten Speicher. (Odergcc -z execstack
links das Programm mit stack + Daten segment + heap ausführbar, als ein quick-hack.)Zerlegen diese, können Sie kompilieren Sie diese, setzen Sie ein label auf die bytes, und ein disassembler.
Kompilieren mit
gcc -c -m32 foo.c
an-und Abbau mitobjdump -D -rwC -Mintel
können wir die Montage, und finden Sie heraus, dass dieser code verletzt das ABI durch Stress EBX (ein Anruf erhaltene register) und ist in der Regel ineffizient.Dieser Maschinencode wird (wahrscheinlich) 32-bit-code auf Windows, Linux, OS X, und so weiter: die Standard-Aufruf-Konventionen auf allen diesen Betriebssystemen pass Argumente auf dem stack statt effizienter in Registern. Aber EBX call-erhalten Sie in den üblichen Aufruf-Konventionen, also der Einsatz als scratch-register, ohne speichern/wiederherstellen Sie können ganz einfach die Anrufer-crash.
Hi Matt! Abhängig von der Optimierung, die der GCC wird oft inline string-Konstanten in das TEXT-segment, so wird diese Arbeit auch auf neueren windows-version zur Verfügung gestellt, die Sie nicht verbieten diese Art der Optimierung. (Wenn ich mich Recht erinnere, wird die MINGW-version wird in der Zeit von meinem post vor über zwei Jahren inlines-string-Literale in der Standard-Optimierung)
könnte mir bitte jemand erklären, was hier passiert? Was sind das für seltsam aussehende string-literalen?
Es sieht aus wie er raw hexadezimale Werte (z.B. '\x00' ist dasselbe wie '/0', Sie sind beide gleich 0) in einen string, dann umwandeln des string in eine C-Funktion einen Zeiger, dann die Ausführung der C-Funktion Zeiger, weil er der Teufel.
hi FUZxxl, ich denke, es könnte variieren, abhängig von den compiler und das Betriebssystem-version. Der obige code scheint zu verlaufen, auf codepad.org; codepad.org/FMSDQ3ME
InformationsquelleAutor
Einer meiner Lieblings-Anwendungen für Funktionszeiger ist so Billig und einfach Iteratoren -
Vereinbart. Alle meine Iteratoren wie folgt Aussehen:
int (*cb)(void *arg, ...)
. Der Rückgabewert der iterator auch lässt mich halt früh (wenn ungleich null).InformationsquelleAutor
Funktion Zeiger werden einfach zu erklären, sobald Sie die basic-declarators:
ID
: - ID ist eine*D
: D Zeiger aufD(<parameters>)
: D Funktion, die<
Parameter>
RückkehrWährend D eine weitere Feststellung gebaut, mit den gleichen Regeln. Am Ende, irgendwo, es endet mit
ID
(siehe unten für ein Beispiel), das ist der name der deklarierten Entität. Wir werden versuchen, zu erstellen eine Funktion, die einen Zeiger auf eine Funktion, die nichts und int Rückkehr und für die Rückgabe einen Zeiger auf eine Funktion, die ein char und zurückgeben. int. Mit type-defs, es ist wie dasWie Sie sehen, es ist ziemlich einfach zu bauen, es mit typedefs. Ohne typedefs, es ist nicht schwer, entweder mit der obigen Feststellung Regeln, konsequent angewandt. Wie Sie sehen, ich verpasste den Teil, der Zeiger zeigt, und das, was die Funktion zurückgibt. Das ist das, was erscheint ganz Links in der Erklärung, und ist nicht von Interesse: Es ist am Ende Hinzugefügt, wenn man die Feststellung schon. Lassen Sie uns das tun. Bau es konsequent, zunächst wortreich - zeigt die Struktur mit
[
und]
:Wie Sie sehen, kann man beschreiben, eine Art ganz durch Anhängen declarators einer nach dem anderen. Die Konstruktion kann auf zwei Arten erfolgen. Man ist bottom-up, beginnend mit dem sehr richtige (Blätter) und arbeiten den Weg durch bis zu der Kennung. Der andere Weg ist, top-down, beginnend mit der identifier, die den Weg nach unten in die Blätter. Ich zeige beide Möglichkeiten.
Bottom-Up -
Bau beginnt mit der Sache zum Recht: Die Sache zurückgegeben, was ist die Funktion, die char. Halten die declarators deutlich, ich werde Nummer:
Eingefügt die char-parameter direkt auf, denn es ist trivial. Hinzufügen eines pointer auf Feststellung durch den Austausch
D1
durch*D2
. Beachten Sie, dass wir zu wickeln Klammern um*D2
. Das kann man durch einen Blick in die Rangfolge der*-operator
und dem Funktions-Aufruf-operator()
. Ohne unsere Klammern, der compiler würde es hier Lesen*(D2(char p))
. Das würde aber nicht um ein einfaches ersetzen von D1 durch*D2
mehr, natürlich. Klammern sind immer erlaubt, um declarators. So müssen Sie nicht machen nichts falsch, wenn Sie zu viel von Ihnen, eigentlich.Rückgabetyp ist komplett! Nun, lassen Sie ersetzen
D2
von der Funktion Feststellung Funktion, die<parameters>
Rückkehr, dieD3(<parameters>)
was wir jetzt sind.Beachten Sie, dass keine Klammern benötigt werden, da wir wollen
D3
eine Funktion-Feststellung und nicht ein Zeiger Nichtigerklärung dieser Zeit. Toll, jetzt müssen Sie nur noch die Parameter für die. Der parameter ist genau das gleiche getan wie wir getan haben, das zurück geben, nur mitchar
ersetzt durchvoid
. So werde ich es kopieren:Habe ich ersetzt
D2
durchID1
, da wir fertig sind mit, dass die parameter (es ist bereits ein Zeiger auf eine Funktion - keine Notwendigkeit für eine weitere Feststellung).ID1
wird der name des Parameters. Nun, ich habe oben schon gesagt, am Ende fügt man die Art, die all jene Feststellung ändern - der eine erscheint ganz Links in jeder Erklärung. Für die Funktionen, das wird der Typ zurückgegeben. Für Hinweise die Spitzen zu geben etc... Es ist interessant, wenn die Schreibweise der Art, erscheint es in umgekehrter Reihenfolge, ganz Recht 🙂 Trotzdem, Sie zu ersetzen-ergibt sich die vollständige Erklärung. Beide Maleint
natürlich.Ich genannt habe, der Bezeichner der Funktion
ID0
in diesem Beispiel.Top-Down -
Dieser beginnt bei der id ganz Links in der Beschreibung der Art, der Verpackung, der Feststellung, wie wir zu Fuß unseren Weg durch das Recht. Beginnen Sie mit Funktion, die
<
Parameter>
RückkehrDas nächste, was in der Beschreibung (nach "die Rückkehr") wurde Zeiger auf. Wir übernehmen es:
Dann die nächste Sache war functon unter
<
Parameter>
Rückkehr. Der parameter ist ein einfacher char, so dass wir es sofort wieder, denn es ist wirklich trivial.Hinweis: die Klammern, die wir Hinzugefügt, da wir wollen, dass die
*
bindet zuerst, und dann die(char)
. Sonst würde es Lesen Funktion, die<
Parameter>
Rückkehr-Funktion .... Nein, die Funktionen zurückgeben Funktionen sind auch nicht erlaubt.Jetzt brauchen wir nur zu setzen
<
Parameter>
. Ich habe eine kurze version des deriveration, da ich denke, dass Sie bereits jetzt auf die Idee, wie es zu tun.Setzen Sie einfach
int
vor der declarators wie wir es mit bottom-up und wir sind fertigDas schöne
Ist bottom-up oder top-down-besser? Ich bin es gewohnt, von unten nach oben, aber manche Leute können mehr Komfort mit top-down. Es ist eine Frage des Geschmacks, denke ich. Übrigens, wenn Sie sich bewerben, dem Betreiber alle in dieser Erklärung werden Sie am Ende immer ein int:
Das ist eine schöne Eigenschaft von Deklarationen in C: Die Erklärung betont, dass, wenn diese Operatoren in einem Ausdruck der Bezeichner, dann bringt es dem Typ ganz Links. So ist es für arrays zu.
Hoffe, Sie mochte dieses kleine tutorial! Jetzt können wir den link zu diesem wenn die Leute Wundern sich über die seltsame Erklärung der syntax von Funktionen. Ich habe versucht, so wenig C-Interna wie möglich. Fühlen Sie sich frei zu Bearbeiten/beheben Dinge.
InformationsquelleAutor
Eine andere gute Verwendung für Funktionszeiger:
Wechseln zwischen Versionen schmerzlos
Sind Sie sehr praktisch zu bedienen, wenn Sie wollen, verschiedene Funktionen zu unterschiedlichen Zeiten oder in unterschiedlichen Phasen der Entwicklung. Zum Beispiel bin ich mir der Entwicklung einer Anwendung auf einem host-computer, eine Konsole, aber die endgültige Version der software wird auf einem Avnet ZedBoard (die hat Anschlüsse für displays und Konsolen, aber Sie sind nicht erforderlich/wollte für die Finale Version). Also während der Entwicklung, ich werde
printf
zum anzeigen von status-und Fehlermeldungen, aber wenn ich fertig bin, will ich nicht alles gedruckt. Hier ist, was ich getan habe:version.h
In
version.c
definiere ich die 2 Funktions-Prototypen präsentieren inversion.h
version.c
Beachten Sie, wie die Funktion Zeiger Prototyp in
version.h
alsvoid (* zprintf)(const char *, ...);
Wenn es auf die in der Anwendung, wird es beginnen die Ausführung, egal wo es gerichtet ist, das muss noch festgelegt werden.
In
version.c
, Ankündigung in derboard_init()
Funktion, wozprintf
ist eine eindeutige Funktion (deren Funktion der Signatur übereinstimmt), abhängig von der version, die definiert ist inversion.h
zprintf = &printf;
zprintf Aufrufe von printf zu debug-Zweckenoder
zprintf = &noprint;
zprintf nur gibt und nicht unnötigen codeLäuft der code wird wie folgt Aussehen:
mainProg.c
Den oben genannten code verwenden
printf
wenn im debug-Modus, oder nichts tun, wenn im release-Modus. Dies ist viel einfacher, als sich durch das gesamte Projekt und auskommentieren oder löschen von code. Alles, was ich tun müssen, ist, ändern Sie die version inversion.h
und der code macht den rest!InformationsquelleAutor
Funktion Zeiger ist in der Regel definiert durch "typedef", und als param & return-Wert,
Obigen Antworten bereits erklärt viel, ich gebe einfach ein komplettes Beispiel:
InformationsquelleAutor
Einer der großen verwendet für Funktionszeiger in C ist der Aufruf einer Funktion ausgewählt, die zur Zeit ausführen. Zum Beispiel, die C run-time Bibliothek hat zwei Routinen,
qsort
undbsearch
, die einen Zeiger auf eine Funktion, die aufgerufen wird, zu vergleichen, zwei Elemente, die sortiert wird; dies ermöglicht Ihnen, zu Sortieren oder zu suchen, bzw. alles, basierend auf irgendwelchen Kriterien, die Sie verwenden möchten.Ein sehr einfaches Beispiel, wenn es eine Funktion namens
print(int x, int y)
die wiederum erfordern eine Funktion aufrufen (entwederadd()
odersub()
, die sind vom selben Typ), dann ist das, was wir tun, werden wir hinzufügen, eine Funktion Zeiger-argument zu, dasprint()
- Funktion, wie unten gezeigt:Ausgabe:
InformationsquelleAutor
Funktion Zeiger ist eine variable, die enthält die Adresse einer Funktion. Da es eine Zeiger-variable, wenn auch mit etwas eingeschränkten Eigenschaften, die Sie verwenden können, es ist ziemlich viel, wie Sie würde jede andere Zeiger-variable im Daten-Strukturen.
Die einzige Ausnahme, die mir einfällt, ist die Behandlung der Funktionszeiger verweisen auf etwas anderes als ein einzelner Wert. Tut Zeiger-Arithmetik durch Inkrementieren oder Dekrementieren einen Funktionszeiger oder das hinzufügen/subtrahieren eines offset an eine Funktion Zeiger ist nicht wirklich von nutzen als eine Funktion Zeiger verweist nur auf eine einzige Sache, den Eintrittspunkt einer Funktion.
Die Größe einer Funktion, die Zeiger-variable, die die Anzahl der bytes belegt, die durch die variable, kann variieren, abhängig von der zugrunde liegenden Architektur, wie z.B. x32 oder x64 oder was auch immer.
Die Deklaration für eine Funktion pointer-variable braucht, um zu geben Sie die gleiche Art von Informationen als eine Funktion Erklärung, um für den C-compiler zu tun, die Arten von checks, die es normalerweise tut. Wenn Sie nicht geben Sie eine parameter-Liste in der Deklaration/definition der Funktion ein Zeiger, der C-compiler nicht in der Lage zu prüfen, die Verwendung von Parametern. Es gibt Fälle, wenn dieser Mangel an Kontrolle kann nützlich sein, aber denken Sie daran, dass ein Sicherheits-Netz wurde entfernt.
Einige Beispiele:
Den ersten beiden declararations sind etwas ähnlich, dass:
func
ist eine Funktion, die einenint
und einchar *
und zurückint
pFunc
ist eine Funktion, die Zeiger auf die zugeordnet ist die Adresse einer Funktion, die einenint
und einchar *
und zurückint
Also von oben konnten wir eine Quell-Zeile, in der die Adresse der Funktion
func()
zugeordnet ist, um den Funktionszeiger-variablepFunc
wie inpFunc = func;
.Beachten Sie die syntax mit einem Funktionszeiger Deklaration/definition in der Klammer sind zu überwinden, die Natürliche Rangfolge der Regeln.
Verschiedene Anwendungsbeispiele
Einige Beispiele der Verwendung der Funktion Zeiger:
Können Sie variable Länge der Parameterliste in der definition eines funktionszeigers.
Oder Sie können nicht geben Sie eine parameter-Liste an alle. Dies kann nützlich sein, aber es entfällt die Möglichkeit der C-compiler Prüfungen an der argument-Liste zur Verfügung gestellt.
C-Stil-Casts
Können Sie die Verwendung von C-Stil-casts mit Funktionszeigern. Beachten Sie jedoch, dass ein C-compiler kann lax über Prüfungen oder geben Warnungen eher als Fehler.
Compare-Funktion Zeiger auf Gleichheit
Können Sie überprüfen, ob eine Funktion Zeiger ist gleich eine bestimmte Funktion Adresse verwenden
if
Aussage aber ich bin nicht sicher, wie nützlich das wäre. Andere Vergleichsoperatoren scheint noch weniger utility.Ein Array von Funktionszeigern
Und wenn Sie wollen, um ein array von Funktionszeigern jedes der Elemente, aus denen die argument-Liste zu Differenzen, dann können Sie eine Funktion definieren, die Zeiger durch die Liste der Argumente unspezifiziert (nicht
void
was bedeutet, dass keine Argumente, sondern nur unspezifisch) so etwas wie die folgenden wenn Sie sehen, Warnungen aus der C-compiler. Dies funktioniert auch für eine Funktion Zeiger-parameter einer Funktion:C-Stil
namespace
Mit Globalenstruct
mit FunktionszeigernKönnen Sie die
static
Schlüsselwort, um eine Funktion anzugeben, deren name Datei-Bereich und weisen Sie diese auf eine Globale variable als eine Möglichkeit, etwas ähnliches wie dienamespace
Funktionalität von C++.In einer Headerdatei definiert eine struct, werden unsere namespace zusammen mit einer globalen variable, die verwendet wird.
Dann in der C-Quelldatei:
Dieser würde dann verwendet werden, durch die Angabe der vollständigen Namen der globalen struct-Variablen und member-Namen, um auf die Funktion zuzugreifen. Die
const
Modifikator verwendet wird, die global auf, so dass es nicht geändert werden können, durch einen Unfall.Anwendungsbereiche von Funktionszeigern
DLL-library-Komponente könnte etwas tun, ähnlich wie die C-Stil
namespace
Ansatz, in dem eine bestimmte library-Schnittstelle angefordert wird, aus einer factory-Methode in einer Bibliothek-Schnittstelle, die unterstützt die Schaffung einesstruct
mit Funktionszeigern.. Das library interface lädt die angeforderte DLL-version schafft eine Struktur, die mit den erforderlichen Funktions-Zeiger, und dann wieder die Struktur an den ersuchenden Anrufer für den Einsatz.und dies könnte verwendet werden, wie in:
Der gleiche Ansatz kann verwendet werden, definieren Sie eine abstrakte hardware-Ebene für den code, der verwendet ein bestimmtes Modell der zugrunde liegenden hardware. Funktion Zeiger sind gefüllt mit hardware-spezifische Funktionen, indem Sie eine Fabrik, um die hardware-spezifischen Funktionen, die Funktionen angegeben, die in der abstrakten hardware-Modell. Dies kann verwendet werden, um eine abstrakte hardware-layer von der software genutzt, die fordert, eine factory-Funktion, um die spezifische Funktion hardware-Schnittstelle verwendet dann die Funktion Zeiger zur Verfügung gestellt, um Aktionen durchzuführen, die für die zugrunde liegende hardware, ohne zu wissen, Implementierungsdetails zu dem bestimmten Ziel.
Funktionszeiger zu erstellen Delegierten, Handlern und Rückrufe
Können Sie verwenden, function Pointer als eine Möglichkeit zum delegieren Sie einige Aufgaben oder Funktionen. Das klassische Beispiel in C ist der Vergleich delegieren Funktion Zeiger verwendet, mit den Standard-C-library-Funktionen
qsort()
undbsearch()
zu bieten, die Sortierung, die Reihenfolge für die Sortierung einer Liste von Elementen oder das ausführen einer binären Suche über eine sortierte Liste von Elementen. Die Vergleich-Funktion delegieren, gibt die Sortierung Algorithmus in der Art, oder die binäre Suche.Andere Verwendung ist ähnlich wie die Anwendung eines Algorithmus in einer C++ - Standard Template Library container.
Weiteres Beispiel ist mit dem GUI-Quelltext, in dem Sie einen handler für ein bestimmtes Ereignis registriert wird, indem eine Funktion Zeiger, die tatsächlich aufgerufen wird, wenn das Ereignis Eintritt. Microsoft MFC-framework, mit Ihrer Botschaft maps verwendet etwas ähnliches in der Handhabung von Windows-Nachrichten, die geliefert werden, zu einem Fenster oder thread.
Asynchrone Funktionen, die erfordern, dass eine callback-sind ähnlich wie ein Ereignis-handler. Die Benutzer des asynchronen Funktion ruft die asynchrone Funktion zu starten, eine Aktion, und stellt eine Funktion Zeiger, die die asynchrone Funktion aufrufen, sobald die Aktion abgeschlossen ist. In diesem Fall ist das Ergebnis der asynchronen Funktion der Vollendung seiner Aufgabe.
InformationsquelleAutor
Ab scratch-Funktion hat Einige Speicher-Adresse, von Wo Aus Sie starten, ausführen. In Assembler Werden Sie genannt (call "- Funktion die Speicher-Adresse").Jetzt kommen Sie zurück zu C, Wenn die Funktion eine Speicheradresse, dann können Sie manipuliert werden mit Hilfe von Zeigern in C. Also nach den Regeln von C
1.Zuerst müssen Sie deklarieren Sie einen Zeiger auf Funktion
2.Übergeben Sie die Adresse der Gewünschten Funktion
****Hinweis->die Funktionen sollten vom selben Typ sein****
Diesem Einfachen Programm wird zeigen Jedes Ding.
Nach, mal Sehen, Wie die Maschine Sie Versteht.Blick von Maschinen Einweisung der oben genannte Programm in der 32-bit-Architektur.
Den rot markieren Bereich, wie die Adresse ausgetauscht wird und die Speicherung in eax.Dann ist eine call-Anweisung auf eax. eax enthält die gewünschte Adresse der Funktion
InformationsquelleAutor
Da Funktionszeiger werden oft eingegeben Rückrufe, möchten Sie vielleicht einen Blick auf typsichere callbacks. Das gleiche gilt für die entry-Punkte, etc. von Funktionen, die nicht callbacks.
C ist ziemlich wankelmütig und versöhnlich zugleich 🙂
InformationsquelleAutor