Reflexionsunterstützung in C
Ich weiß, es wird nicht unterstützt, aber ich Frage mich, ob es irgendwelche tricks um ihn herum. Irgendwelche Tipps?
InformationsquelleAutor der Frage adk | 2009-08-30
Du musst angemeldet sein, um einen Kommentar abzugeben.
Reflexion im Allgemeinen ist ein Mittel für ein Programm zum analysieren der Struktur von code.
Diese Analyse wird benutzt, um das effektive Verhalten der code.
Reflexion als Analyse ist in der Regel sehr schwach; in der Regel kann es nur geben Zugang zu Funktion und Feld-Namen. Diese Schwäche kommt von der Sprache der Implementierer im wesentlichen nicht wollen, um den vollständigen source code zur Laufzeit, zusammen mit der entsprechenden Analyse-Routinen zum extrahieren, was will man aus dem source code.
Einem anderen Ansatz anzugehen program analysis Kopf auf, mit einem starken Programm-Analyse-tool, z.B., eine, parse den Quelltext genau so, wie der compiler das macht.
(Die Leute oft schlagen, um den Missbrauch der compiler selbst um dies zu tun, aber in der Regel nicht funktionieren; der compiler Maschinen will ein compiler und es ist verdammt schwer zu biegen es für andere Zwecke verwendet werden).
Was benötigt wird, ist ein tool, dass:
(Es ist hilfreich, wenn die ASTs behalten, Kommentare und andere details der Quelle
code-layout wie Spalte zahlen, literal, Basis-Werte, etc.)
(in der Regel durch die Revision des ASTs vertreten, dass der Analysierte code)
die überarbeitete ASTs.
Verwendung solcher Maschinen, setzt die Analyse auf jeder Ebene der Details notwendig ist, und dann verwandelt sich der code, um den Effekt zu erzielen, die Laufzeit Reflexion erledigen würde.
Es gibt mehrere wichtige Vorteile:
das begrenzt, was der Laufzeit kann die Reflexion nur)
als beschränkt auf das, was eine bestimmte Sprache bietet die Implementierung.
Wenn Sie brauchen nicht nachdenken, Sie brauchen nicht diese Maschinen. Und Ihre Sprache
braucht nicht auf das geistige Gepäck der schwachen Reflexion erbaut.
Finden Sie unsere DMS Software Reengineering Toolkit für ein system, das alle der oben für C, Java und COBOL, und die meisten es für C++.
InformationsquelleAutor der Antwort Ira Baxter
Der compiler wird vermutlich Optional erzeugen Sie "debug-symbol-Datei", die einen debugger verwenden können, um debug-code. Der linker generiert möglicherweise auch eine "map-Datei".
Einen trick/Tipp sein könnte zu generieren, und dann diese Dateien Lesen.
InformationsquelleAutor der Antwort ChrisW
Basiert auf den Antworten zu Wie kann ich Reflexion an einer C++ - Anwendung? (Stack-Overflow) und die Tatsache, dass C++ ist eine "übermenge" von C, ich würde sagen, Sie sind aus Glück heraus.
Gibt es auch eine nette lange Antwort über warum C++ nicht über Reflexion (Stack-Overflow).
InformationsquelleAutor der Antwort Andrew Keeton
Ich brauchte Reflexion in einer Reihe von
struct
s in ein C++ - Projekt.Ich erstellte eine xml-Datei mit der Beschreibung all jener Strukturen, die glücklicherweise die Felder-Typen primitive Typen.
Habe ich eine Vorlage (nicht C++
template
) zum automatischen erzeugen einerclass
für jedenstruct
zusammen mit setter - /getter-Methoden.In jedem
class
habe ich eine Karte zuordnen string Namen und Klasse Mitglieder (Zeiger auf Mitglieder).Ich nicht bereut habe mit der spiegelung, weil es eröffnet neue Möglichkeiten, um das design für meine core-Funktionalität, die ich nicht einmal vorstellen konnte, ohne Reflexion.
(BTW, es war eine externe report-generator für ein Programm, das mit einer raw Datenbank)
Also benutzte ich die code-Generierung, Funktion, Hinweise und Karten zu simulieren, Reflexion.
InformationsquelleAutor der Antwort Nick Dandoulakis
Tipps und tricks, die immer vorhanden ist. Werfen Sie einen Blick auf Metaresc Bibliothek https://github.com/alexanderchuranov/Metaresc
Es bietet eine Schnittstelle für die Typen-Deklaration generieren auch meta-Daten für den Typ. Basierend auf meta-Daten können Sie ganz einfach serialisieren/Deserialisieren von Objekten beliebiger Komplexität. Aus der box können Sie serialisieren/Deserialisieren von XML -, JSON -, XDR, Lisp-ähnliche notation, C-init-notation.
Hier ist ein einfaches Beispiel:
Diesem Programm wird die Ausgabe
Bibliothek funktioniert gut für die neuesten gcc-und clang.
InformationsquelleAutor der Antwort Herman Narkaytis
Würden Sie brauchen, um es zu implementieren, von selbst aus dem Boden auf. Gerade C, es gibt keine Laufzeit-Informationen auch immer gehalten an Struktur-und composite-Typen. Metadaten einfach nicht vorhanden in der standard.
InformationsquelleAutor der Antwort Crashworks
InformationsquelleAutor der Antwort Artyom
Ich kenne die folgenden Optionen, aber alle kommen an Kosten und eine Menge von Einschränkungen:
libdl
(#include <dfcln.h>
)objdump
odernm
Werde ich ein wenig von unit-test-frameworks, wie Beispiele weiter unten, da die automatische test-Erkennung für unit-test-frameworks ist ein typisches Beispiel wo die Reflexion kommt in sehr praktisch, und es ist etwas, dass die meisten unit-test-frameworks für C unterschreiten.
Mit
libdl
(#include <dfcln.h>
) (POSIX)Wenn man auf einem POSIX-Umgebung, ein wenig Reflexion kann man mit Hilfe
libdl
. Plugins sind entwickelt auf diese Weise.Verwenden
in Ihrem source-code und link mit
-ldl
.Dann haben Sie Zugriff auf Funktionen
dlopen()
dlerror()
dlsym()
unddlclose()
mit denen man laden kann und Zugriff /das ausführen von gemeinsamen Objekten zur Laufzeit. Jedoch, es nicht geben Ihnen einen einfachen Zugriff auf die Symboltabelle.Ein weiterer Nachteil dieses Ansatzes ist, dass Sie im Grunde beschränken Reflexion auf Objekte geladen, die als dynamische Bibliothek (shared object zur Laufzeit geladen wird über
dlopen()
).Läuft
nm
oderobjdump
Kann
nm
oderobjdump
zu zeigen das symbol Tabelle und analysieren Sie die Ausgabe.Für mich
nm -P --defined-only -g xyz.o
liefert gute Ergebnisse, und das Parsen der Ausgabe ist trivial.Sie interessiert sich zwar für das erste Wort jeder Zeile nur den Namen des symbols, und vielleicht auch die zweite, die den Typ des Abschnitts.
Wenn Sie nicht wissen, den Namen des Objekts in statischen, d.h. das Objekt ist eigentlich ein shared object, zumindest auf Linux sollte man dann vielleicht möchten Sie zu überspringen-symbol Namen beginnend mit '_'.
objdump
nm
oder ähnliche tools werden oft auch außerhalb der POSIX-Umgebungen.Analyse der Objekt-Dateien selbst
Könnten Sie analysieren die Objekt-Dateien selbst. Sie wollen wahrscheinlich nicht zu implementieren, die von Grund auf neu, sondern verwenden Sie eine vorhandene library. Dies ist, wie
nm
objdump
und sogarlibdl
umgesetzt werden. Sie könnten Blick auf den source-code vonnm
objdump
undlibdl
und den Bibliotheken, die Sie verwenden, um herauszufinden, wie Sie tun, was Sie tun.Mit einem Parser
Könnten Sie schreiben Sie einen parser und code-generator erzeugt die notwendigen reflektierende Informationen zur compile-Zeit und speichert Sie in der Objekt-Datei. Dann haben Sie eine Menge Freiheit und könnte sogar implementieren primitive Formen von Annotationen. Das ist es, was einige unit-test-frameworks wie AceUnit tun.
Fand ich, dass das schreiben eines parsers umfasst straight-forward C-syntax ist ziemlich trivial. Schreiben Sie einen parser, der wirklich versteht C und konnte sich mit allen Fällen, ist NICHT trivial.
So, das hat Grenzen, die davon abhängen, wie exotisch der C-syntax ist, dass Sie möchten, zu reflektieren.
"Missbrauchen" den linker zu erzeugen symbol-arrays
Könnte man Referenzen auf Symbole, die Sie wollen, zu reflektieren, in einen besonderen Abschnitt, und verwenden Sie ein linker-Konfiguration wieder den Abschnitt Grenzen, so können Sie auf Sie zugreifen, C.
Habe ich hier beschrieben N-Dependency injection in C - besser Weg als linker-arrays definiert?wie das funktioniert.
Aber Vorsicht, dies ist abhängig von einer Menge Dinge, und nicht sehr portabel. Ich habe nur versucht, diese mit
GCC
/ld
und ich weiß, es funktioniert nicht mit allen Compilern /linkern. Außerdem ist es fast garantiert, dass die dead code elimination wird nicht erkennen, wie nennen Sie diese Sachen, also, wenn Sie verwenden, dead code elimination, müssen Sie alle die reflektierte Symbole als Einstiegspunkte.Fallstricke
Für einige der Mechanismen, dead code elimination kann ein problem sein, vor allem, wenn man "Missbrauch" der linker generiert eine symbol-arrays. Es kann umgangen werden, indem der reflektierte Symbole als Einstiegspunkte an den linker, und je nach der Menge der Symbole dieses könnte weder schön, noch bequem.
Abschluss
Kombination
nm
undlibdl
tatsächlich geben Recht gute Ergebnisse. Die Kombination kann fast so mächtig wie die Ebene der Reflexion verwendet, die von JUnit 3.x in Java. Die Ebene der Reflexion gegeben ist ausreichend, um implementieren Sie eine JUnit-3.x-style unit-test-framework für C, einschließlich test-Fall der Entdeckung durch die Namenskonvention.Denen ein parser ist mehr Arbeit und beschränkt sich auf Objekte, die Sie selbst kompilieren, aber gibt Ihnen die meiste Energie und Freiheit. Die Ebene der Reflexion gegeben werden kann, ausreichend, um implementieren Sie eine JUnit-4.x-style unit-test-framework für C, einschließlich test-Fall der Entdeckung durch die Anmerkungen. AceUnit ist ein unit-test-framework für C, die tut genau dies.
Kombination von Analyse und linker erzeugen symbol-arrays, können damit sehr schöne Ergebnisse erzielen - wenn Sie Ihre Umwelt so sehr unter Ihrer Kontrolle, können Sie sicherstellen, dass die Arbeit mit den linker, die Art und Weise für Sie arbeitet.
Natürlich können Sie kombinieren alle Ansätze Stich zusammen die bits und Stücke, bis Sie Ihren Bedürfnissen anpassen.
InformationsquelleAutor der Antwort Christian Hujer
Nur machen, unabhängig von der Art der formschlüssigen Tabelle, Baum, verkettete Liste oder was auch immer Sammlung, die Sie sind komfortabel mit der Verwaltung oder finden Sie, um wirksam zu sein. Fügen Sie einen Schlüssel, ob string, Typ/id-combo oder ähnliches und darauf die Adresse einer Funktion oder Struktur. Ein super-naive version von Reflexion kann auch eine Sammlung von folgenden:
Mit eine große ol' switch-Fall, wo Sie einen handler für jeden Typ oder name oder Makros zu tun, befestigen Sie die gleichen. Alternativ bringen Sie immer Funktionen, die Empfänger, was in Ihrem reflectable struct, das sind die gleichen wie die Handler, aber mit mehr von einem dispatch-Modell direkt auf den container.
InformationsquelleAutor der Antwort Garet Claborn