Wie erreichen Sie das überladen von Funktionen in C?
Gibt es eine Möglichkeit zu erreichen, überladen von Funktionen in C? Ich bin auf der Suche einfache Funktionen zu überladen werden, wie
foo (int a)
foo (char b)
foo (float c , int d)
Ich denke, es ist keine gerade, vorne Weg; ich bin auf der Suche nach workarounds, wenn vorhanden.
- Warum würden Sie wollen, dies zu tun? C hat keine polymorphen Fähigkeiten. Also foo(random-Typ) ist es unmöglich. Nur echte funcs foo_i, foo_ch, foo_d, etc.
- Können Sie gehen den bösen Weg mit void-Zeigern und Typ-ids.
- Ich habe das Gefühl, ich sollte die Aufmerksamkeit auf die Tatsache, dass die Antwort auf diese Frage hat sich verändert, seit es wurde ursprünglich gestellte, mit dem neuen C-standard.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Gibt es einige Möglichkeiten:
man 2 open
beideopen()
undopenat()
hat zwei Signaturen, mit oder ohnemode
argument.open()
sorgfältig, werden Sie feststellen, dass ob dermode
argument verwendet wird, kann bestimmt werden aus den Werten der früheren Argumente.mode
ist nie zu0
oder einige andere Standard - es ist unbenutzt. Aufgrund der C-Aufrufkonvention aufrufen einer Funktion mit weniger Parametern ergibt sich die fehlenden Parameter als Müll, aber die bereitgestellten Parameter bleiben unberührt. Daheropen()
undopenat()
können einfach definiert werden als eine normale Funktion mit allen Parametern vorhanden, ohne zu überladen.Ja!
In der Zeit seit diese Frage gestellt wurde, standard C (keine Erweiterungen) hat effektiv gewonnen Unterstützung für das überladen von Funktionen (nicht Betreiber), Dank der Ergänzung des
_Generic
Schlüsselwort in C11. (unterstützt GCC seit version 4.9)(Überladen ist nicht wirklich "built-in" in der Mode gezeigt, in der Frage, aber es ist tot einfach, etwas umzusetzen, das funktioniert so.)
_Generic
ist eine compile-time-operator in der gleichen Familie wiesizeof
und_Alignof
. Es ist beschrieben in der standard-Abschnitt 6.5.1.1. Es nimmt hauptsächlich zwei Parameter: einen Ausdruck (das nicht zur Laufzeit ausgewertet), und ein Typ/Ausdruck, Vereins-Liste, die ein bisschen aussieht wie eineswitch
block._Generic
bekommt die insgesamt Typ des Ausdrucks-und dann der "Schalter" auf, um die gewünschte end-Ergebnis-Ausdruck in der Liste für seinen Typ:Den oben genannten Ausdruck zu
2
- die Art der Kontrolle der expression istint
, so wählt er den Ausdruck im Zusammenhang mitint
als Wert. Nichts bleibt zur Laufzeit. (Diedefault
- Klausel ist optional: wenn Sie lassen Sie es aus und geben Sie nicht übereinstimmen, wird es zu einem Kompilierungsfehler.)Dem Weg dies ist nützlich für das überladen von Funktionen ist, dass es eingefügt werden kann, die durch den C-Präprozessor und wählen Sie eine Ergebnis-Ausdruck, basierend auf dem Typ der übergebenen Argumente die controlling-makro. So (Beispiel aus der C-standard):
Dieses makro implementiert eine überladene
cbrt
Betrieb, mit dem Versand auf den Typ des Arguments, um die makro -, die Wahl einer geeigneten Implementierung der Funktion, und übergeben Sie das original-makro-argument für diese Funktion.So zu implementieren, die Ihre ursprünglichen Beispiel, wir könnten dies tun:
In diesem Fall könnten wir verwendet haben, ein
default:
Verein für den Dritten Fall, das heißt aber nicht zeigen, wie zu erweitern, das Prinzip auf mehrere Argumente. Das Endergebnis ist, dass Sie verwenden könnenfoo(...)
im code, ohne sich Gedanken (viel[1]) über die Art seiner Argumente.Für kompliziertere Situationen, z.B. Funktionen überladen größere Anzahl Argumente oder unterschiedliche zahlen, die Sie verwenden können, utility-Makros zur automatischen Generierung von statischen Strukturen Versand:
(Umsetzung hier) Also mit etwas Aufwand können Sie reduzieren die Menge an boilerplate zu suchen, so ähnlich wie eine Sprache, mit nativer Unterstützung für überlastung.
Nebenbei, es war schon möglich zu einer übersteuerung der Anzahl der Argumente (nicht die Art) in C99.
[1] beachten Sie, dass der Weg C wertet Arten möglicherweise Reise, die Sie bis obwohl. Diese wählen
foo_int
wenn Sie versuchen, geben Sie ein Zeichen-literal, zum Beispiel, und Sie müssen über ein bisschen Durcheinander wenn Sie möchten, dass Ihre überlastungen zu unterstützen string-Literale. Noch insgesamt ziemlich cool wenn.switch
block", ich dachte, Sie wurden sagen, dass er aussieht wie eine, sondern ist auch etwas anders ein, inwieweit man sollte nicht denken, der es so (obwohl Sie es erklärt im nächsten Satz), so verwirrt, dass Sie mich für eine minute. Es im Grunde genommen ist einswitch
- Anweisung, die zur Laufzeit ausgewertet. Es macht jetzt Sinn. Danke!__VA_ARGS__
... ich konnte es arbeitet mit(SECOND(0, ##__VA_ARGS__, 0)
stattFIRST
und(_1, ## __VA_ARGS__)
für die Argumente der Funktion rufen Sie Die genanntendefault
Lösung funktioniert gut, obwohl. Wie würden Sie lösen eine zusätzliche überlastungfoo_float(float)
???Wie gesagt, überladen in dem Sinne, dass du meinst, wird nicht unterstützt von C. Ein gemeinsames idiom, das problem zu lösen ist, die die Funktion annehmen tagged union. Dies wird implementiert, indem ein
struct
parameter, wo diestruct
selbst besteht aus eine Art Art Anzeige, wie einenum
, und einunion
von den verschiedenen Arten von Werten. Beispiel:whatever
s in separate Funktionen (set_int
,set_float
, etc). Dann "tagging" mit dem Typ" wird zu "add Art-name der Funktion-name". Die version in dieser Antwort geht es um mehr Typisierung, mehr Laufzeit Kosten, mehr Chancen auf Fehler, die nicht gefangen werden zur compile-Zeit... ich kann nicht erkennen, überlegenheit, Dinge zu tun auf diese Weise! 16 upvotes?!set_int
,set_float
usw ...Wenn Ihr compiler ist gcc und Sie nichts dagegen tun hand, updates jedes mal, wenn Sie hinzufügen eine neue überladung können Sie einige makro-Magie und bekommen das Ergebnis Sie wollen im Sinne der Anrufer, es ist nicht so schön zu schreiben... aber es ist möglich
schauen, __builtin_types_compatible_p, dann definieren Sie ein makro, das so etwas macht
aber ja böse, weiß nur nicht
EDIT: C1X werden, Unterstützung zu bekommen für die Art generische Ausdrücke, die Sie wie folgt Aussehen:
Hier ist der klarste und prägnanteste Beispiel, das ich gefunden habe, die belegen das überladen von Funktionen in C:
https://gist.github.com/barosl/e0af4a92b2b8cabd05a7
Ja, irgendwie schon.
Hier gehen Sie durch ein Beispiel :
Wird der Ausgang 0 und Hallo .. von printA-und printB.
Den folgenden Ansatz ist ähnlich a2800276's, aber mit einigen C99-makro-Magie Hinzugefügt:
Dies kann nicht helfen, aber wenn Sie mit clang können Sie die overloadable Attribut - Dies funktioniert sogar, wenn das kompilieren als C
http://clang.llvm.org/docs/AttributeReference.html#overloadable
Header
Umsetzung
In dem Sinne, du meinst — Nein, du nicht.
Können Sie erklären, ein
va_arg
Funktion wievoid my_func(char* format, ...);
aber du wirst dich übergeben zu müssen, irgendeine Art von Informationen über die Anzahl der Variablen und deren Typen in die erste argument — wie
printf()
tut.Normalerweise eine Warze zu geben Sie den Typ angehängt oder vorangestellt, um die Namen. Sie können sich mit Makros ist einige Instanzen, sondern hängt davon ab, was Sie zu tun versuchen. Es gibt keinen Polymorphismus in C, nur Zwang.
Einfache generische Operationen mit Makros gemacht:
Wenn Ihr compiler unterstützt typeof, kompliziertere Operationen können in das makro. Sie können dann das symbol foo(x) um den gleichen Betrieb verschiedene Arten, aber Sie können nicht unterscheiden, die das Verhalten zwischen den verschiedenen überladungen. Wenn Sie möchten, dass die eigentlichen Funktionen statt Makros, die Sie vielleicht in der Lage sein, um fügen Sie der Typ, um den Namen und verwenden Sie eine zweite einfügen in access (ich habe nicht versucht).
Leushenko Antwort ist wirklich cool - nur: die
foo
Beispiel nicht kompilieren mit GCC zu erklären, die nicht auffoo(7)
, stolpern über dieFIRST
makro-und der eigentliche Funktionsaufruf ((_1, __VA_ARGS__)
, die restlichen mit einem überschuss Komma. Darüber hinaus sind wir in Schwierigkeiten, wenn wir wollen, um zusätzliche überlastungen, wiefoo(double)
.Also habe ich beschlossen zu erarbeiten, die Antwort ein wenig weiter, einschließlich zu ermöglichen, eine leere überlast (
foo(void)
– das verursacht ziemliche Probleme...).Idee ist nun: Definieren Sie mehr als einen generic in verschiedenen Makros und lassen Sie die richtige wählen entsprechend der Anzahl der Argumente!
Anzahl der Argumente ist ganz einfach, basierend auf diese Antwort:
Das ist schön, wir beschließen, uns entweder
SELECT_1
oderSELECT_2
(oder mehr Argumente, wenn Sie wollen/brauchen), so müssen wir einfach angemessen definiert:OK, ich habe die leere überlastung schon – allerdings, das man eigentlich nicht unter die C-standard, die nicht in die leere Variable Argumente, ich. e. wir haben dann verlassen sich auf compiler-Erweiterungen!
Auf den ersten, wird ein leeres makro aufrufen (
foo()
) produziert immer noch ein token, aber ein leerer. So zählen die makro-tatsächlich gibt 1 statt 0 auch leer makro aufrufen. Wir können "einfach" beseitigen Sie dieses problem, wenn wir das Komma nach__VA_ARGS__
bedingt, je nach Liste leer ist oder nicht:Dass sah einfach, aber die
COMMA
makro ist ziemlich schwer; zum Glück, das Thema ist bereits bedeckt in einem blog von Jens Gustedt (danke, Jens). Grundlegende trick ist, die Funktion Makros werden nicht expandiert, wenn nicht gefolgt von Runden Klammern, weitere Erklärungen haben Sie einen Blick auf Jens' blog... Wir müssen einfach ändern Sie die Makros ein wenig auf unsere Bedürfnisse (ich werde verwenden Sie kürzere Namen und weniger Argumente für die Kürze).Und jetzt sind wir in Ordnung...
Den vollständigen code in einen block:
Können Sie nicht einfach mit C++ und nicht mit allen anderen C++ - Funktionen außer dieser?
Wenn es immer noch nicht nur strenge C, dann würde ich empfehlen variadischen Funktionen statt.
Versuchen zu erklären, diese Funktionen als
extern "C++"
wenn Ihr compiler dies unterstützt, http://msdn.microsoft.com/en-us/library/s6y4zxec(VS.80).aspxIch hoffe, der code unten wird Ihnen helfen, zu verstehen, überladen von Funktionen