Die @encode-Direktive gibt ein const char * zurück, das ein codierter Typdeskriptor der verschiedenen Elemente des Datentyps ist, der übergeben wurde. Beispiel folgt:
%Vor%Ich konnte mithilfe von sizeof () primitive Typen bestimmen - und wenn es ein vollständiges Objekt wäre, könnte ich die Klassenmethoden verwenden, um Introspektion zu machen.
Wie bestimmt es jedoch jedes Element einer undurchsichtigen Struktur?
@Lothars Antwort könnte "zynisch" sein, aber es ist leider ziemlich nah dran. Um etwas wie @encode()
zu implementieren, benötigen Sie einen vollständigen Parser, um die Typinformationen zu extrahieren. Nun, zumindest für etwas anderes als "trivial" @encode()
-Anweisungen (d. H.% Co_de%). Moderne Compiler haben in der Regel entweder zwei oder drei Hauptkomponenten:
Das Front-End muss den gesamten Quellcode analysieren und wandelt den Quelltext im Grunde in ein internes "machine usable" -Formular um.
Das Backend übersetzt das interne, "machine usable" -Formular in ausführbaren Code.
Compiler, die ein "intermediate end" haben, tun dies typischerweise aus irgendeinem Grund: Sie unterstützen mehrere "Frontends", die möglicherweise aus völlig verschiedenen Sprachen bestehen. Ein weiterer Grund ist die Vereinfachung der Optimierung: Alle Optimierungsdurchgänge arbeiten an der gleichen Zwischendarstellung. Die @encode(char *)
-Compiler-Suite ist ein Beispiel für einen "dreistufigen" Compiler. gcc
könnte als "Zwischen- und Backend" -Stufencompiler betrachtet werden: Die "Low-Level-VM" ist die Zwischenrepräsentation und die gesamte Optimierung findet in dieser Form statt. llvm
kann es auch bis zur letzten Sekunde in dieser Zwischendarstellung behalten - dies ermöglicht eine "Linktime-Optimierung". Der llvm
-Compiler ist wirklich ein "Frontend", das (effektiv) clang
Zwischendarstellung ausgibt.
Wenn Sie also llvm
-Funktionalität zu einem 'existierenden' Compiler hinzufügen wollen, müssen Sie es wahrscheinlich als 'Quelle zu Quelle' 'Compiler / Präprozessor' verwenden. So wurden die ursprünglichen Compiler für Objective-C und C ++ geschrieben - sie analysierten den Quelltext der Eingabe und wandelten ihn in "plain C" um, das dann in den Standard-C-Compiler eingespeist wurde. Es gibt ein paar Möglichkeiten, dies zu tun:
@encode()
und yacc
, um einen ANSI-C-Parser zusammenzustellen. Sie brauchen eine Grammatik ANSI C-Grammatik (Yacc) ist eine gute Anfang. Eigentlich, um es klar zu sagen, wenn ich lex
sage, meine ich wirklich bison und yacc
. Und auch, lose, die anderen verschiedenen flex
und yacc
mögen C-basierte Tools: Zitrone , dparser , etc ... lex
mit Yapp oder EYapp , die Pseudo perl
Klone in yacc
sind. Wahrscheinlich besser für das schnelle Prototyping einer Idee im Vergleich zu C-based perl
und yacc
- es ist immerhin lex
: Reguläre Ausdrücke, assoziative Arrays, keine Speicherverwaltung, etc. Hinweis: Ich habe keine persönlichen Erfahrungen mit einem dieser Tools, um etwas wie perl
hinzuzufügen, aber ich vermute, dass sie eine große Hilfe sein würden.
@Lothar macht einen guten Punkt in seinem Kommentar. Eigentlich wollte ich @encode()
einbeziehen, aber es sieht so aus, als wäre es auf dem Weg verloren gegangen.
lcc
C-Compiler. Dies ist ein C-Compiler, der zumindest hinsichtlich der Quellcode-Größe besonders klein ist. Es hat auch ein Buch , das ich sehr empfehlen kann. lcc
C-Compiler. Nicht ganz so pädagogisch wie tcc
, aber auf jeden Fall immer noch sehenswert. lcc
Objective-C-Compiler. Dies ist ein "Quelle zu Quelle" Objective-C-Compiler. Es analysiert den Objective-C-Quellcode und gibt einen C-Quellcode aus, den er dann an poc
(gut, normalerweise gcc
) übergibt. Hat eine Anzahl von Objective-C Erweiterungen / Features, die nicht in gcc
verfügbar sind. Auf jeden Fall einen Besuch wert. Eine Möglichkeit wäre, einen Präprozessor zu schreiben, der den Quellcode für die Typdefinitionen liest und auch @encode
... durch das entsprechende Zeichenfolgenliteral ersetzt.
Ein anderer Ansatz, wenn Ihr Programm mit -g
kompiliert wird, wäre das Schreiben einer Funktion, die die Typdefinition zur Laufzeit aus den Debug-Informationen des Programms liest oder gdb
oder ein anderes Programm verwendet, um sie für Sie zu lesen und dann formatieren Sie es wie gewünscht. Der Befehl gdb
ptype
kann verwendet werden, um die Definition eines bestimmten Typs zu drucken (oder wenn dies nicht ausreicht, gibt es auch maint print type
, das sicher viel mehr Informationen ausgibt, als Sie möglicherweise möchten).
Wenn Sie einen Compiler verwenden, der Plugins unterstützt (zB GCC 4.5), kann es auch möglich sein, einen zu schreiben Compiler-Plugin dafür. Ihr Plugin könnte dann die Typinformationen nutzen, die der Compiler bereits analysiert hat. Offensichtlich wäre dieser Ansatz sehr compilerspezifisch.
Tags und Links c objective-c implementation encode