Moin Moin, folgende Situation: Ich habe eine Software, die an einigen Stellen Enums nutzt. Diese Enums werden teilweise auch in Logdaten gespeichert (numerisch). Die Enums kann ich nicht auf dem µC schon von der Zahl in einen String wandeln, weil ich dafür in den Logdaten zu wenig Speicherplatz habe (das Format kann ich nicht ändern). Da eh ein Tool genutzt wird um die Logdaten später auszuwerten war meine Idee, darin die Enums in Text zu wandeln. Diese Umwandlung könnte ich jetzt natürlich von Hand pflegen - möchte ich aber nicht. Aufgrund von unterschiedlichen Sprachen kann ich leider die Enums auch nicht einfach in dem Tool includieren. Mein Gedanke war jetzt die Enums als Tabelle zu exportieren um diese Tabelle dann in dem Tool zu nutzen. Aber wie mache ich das? Kennt jemand ein Tool um das zu machen? Was mir grade in den Sinn kommt, wäre alle Header mit diesen Enums in ein C++ Tool (Qt kann da über den Moc ja bissl was zaubern) zu includieren und darin die Header ein eine entsprechende Tabelle zu wandeln. Aber ich wäre da für eine einfachere Lösung durchaus offen... ;-) Viele Grüße Michael
:
Bearbeitet durch User
Es gibt diverse Tricks, das in C++ hinzubekommen. Dementsprechend könntest du deine enums zentral in eine Header-Datei packen und diese im uC-Code inkludieren und normal verwenden. Auf dem PC inkludierst du die Datei in ein C++-Programm welches einen dieser Tricks nutzt: https://stackoverflow.com/questions/28828957 Ggf. müssen die genutzten Makros so angepasst werden, dass sie im C-Fall nur das enum produzieren, im C++-Fall zusätzlich das drumherum.
Code generieren. Enum z.B. in einem Python/Ruby/Sprache deiner Wahl definieren und Skript schreiben welches die Enumdefinition für den uC und das Tool (in anderer Sprache) erzeugt.
Bartli schrieb: > Code generieren. Enum z.B. in einem Python/Ruby/Sprache deiner Wahl > definieren und Skript schreiben welches die Enumdefinition für den uC > und das Tool (in anderer Sprache) erzeugt. So grauslich die ganzen aktuellen "Reflection" Implementierungen auch sein mögen, sie sind immer noch besser als externe Tools und Skripts. Es ist einfach ein Naturgesetz, dass Code und externe Skripts irgendwann auseinanderlaufen... Schau mal da rein: https://www.youtube.com/watch?v=GCkhcT2oxCA Das ist so ziemlich state-of-the-art was Enum Stringifizierung usw. angeht.
Patrick C. schrieb: > Versuche mal Doxygen Damit kann man übrigens nicht nur so Sachen wie HTML oder PDF erzeugen, sondern auch eine XML-Datei, die alle im Code erkannten Dinge in XML speichert. Da findet man auch den enum und alle seine Enumeratoren wieder. Ist allerdings ein schon eher zu gesprächiges XML. Vincent H. schrieb: > Bartli schrieb: >> Code generieren. Enum z.B. in einem Python/Ruby/Sprache deiner Wahl >> definieren und Skript schreiben welches die Enumdefinition für den uC >> und das Tool (in anderer Sprache) erzeugt. Ja, so würde ich das auch machen. > So grauslich die ganzen aktuellen "Reflection" Implementierungen auch > sein mögen, sie sind immer noch besser als externe Tools und Skripts. Es > ist einfach ein Naturgesetz, dass Code und externe Skripts irgendwann > auseinanderlaufen... Wie sollen sie das tun, wenn der Code durch dieses externe Skript erzeugt wird? Ich kann dann gar keine enum-Werte benutzen, die nicht vorher vom Skript generiert worden sind. > Schau mal da rein: > Youtube-Video "CppCon 2018: Nir Friedman “Wise Enum: A C++ Smart Enum > For All Your Reflective Enum Needs”" > > Das ist so ziemlich state-of-the-art was Enum Stringifizierung usw. > angeht. Frage ncht gelesen? Oder kannst du erklären, wie man das gleichzeitig in zwei verschiedenen Sprachen und auf zwei Systemen (von denen eins ein µC ist) verteilt nutzt?
Ich benutze dafür "C-Scripte", also Formulierungen in C, die mit verschiedenen, teilweise per Textfresser generierten C-Dateien (konsolapplikatiinen) kompiliert und gestartet werden und text-Output erzeugen. Vorteil: vollständig im Makeprozess scriptbar, also keine Klicks hier und da. Und innerhalb der Programmiersprache, nicht außerhalb. Dadurch wartbar, flexibel und einfache Prüfungen.
Rolf M. schrieb: > Oder kannst du erklären, wie man das gleichzeitig in > zwei verschiedenen Sprachen und auf zwei Systemen (von denen eins ein µC > ist) verteilt nutzt? Dr. Sommer schrieb: > Dementsprechend > könntest du deine enums zentral in eine Header-Datei packen und diese im > uC-Code inkludieren und normal verwenden. Auf dem PC inkludierst du die > Datei in ein C++-Programm welches einen dieser Tricks nutzt
Rolf M. schrieb: > Wie sollen sie das tun, wenn der Code durch dieses externe Skript > erzeugt wird? Ich kann dann gar keine enum-Werte benutzen, die nicht > vorher vom Skript generiert worden sind. Und was hindert irgendwen dran in dem erzeugten Code einen Enum Wert hinzuzufügen? Ich bin zwar im Normalfall schon ein Freund von "richtiges Werkzeug" usw., aber grad in so einem Fall sollte man imho möglichst viel im Code lassen und so wenig wie möglich über Skripts lösen. > Frage ncht gelesen? Oder kannst du erklären, wie man das gleichzeitig in > zwei verschiedenen Sprachen und auf zwei Systemen (von denen eins ein µC > ist) verteilt nutzt? Zwei Systeme wären wohl kein Problem, den Teil mit den zwei Sprachen hab ich aber leider sehr wohl überlesen.
Was das Extrahieren von enums anbelangt, kann evt. ctags behilflich sein: ctags -f - --fields=K --C-kinds=e include/*.h sources/*.c | awk -e '{print $4,$6}'
Vincent H. schrieb: > Rolf M. schrieb: >> Wie sollen sie das tun, wenn der Code durch dieses externe Skript >> erzeugt wird? Ich kann dann gar keine enum-Werte benutzen, die nicht >> vorher vom Skript generiert worden sind. > > Und was hindert irgendwen dran in dem erzeugten Code einen Enum Wert > hinzuzufügen? Die Datei hat einen Namen und/oder liegt in einem Verzeichnis, woraus sofort erkennbar ist, dass sie autogeneriert ist. Im Code steht zusätzlich oben ein auffälliger Kommentar, dass diese Datei autogeneriert wird und das Buildsystem sie überschreibt. Das tut es dann auch. Sobald also jemand das alles ignoriert und trotzdem da einen Wert hinzufügt, ist der beim nächsten Compiler-Lauf wieder weg, und man bekommt bei Benutzung dieses Wertes einen Fehler. > Ich bin zwar im Normalfall schon ein Freund von "richtiges > Werkzeug" usw., aber grad in so einem Fall sollte man imho möglichst > viel im Code lassen und so wenig wie möglich über Skripts lösen. Wenn es denn nur an einer Stelle wäre bzw. wenn der Code an allen Stellen der gleiche wäre. Aber das ist hier nicht der Fall. Es gibt zwei Stellen, die was unterschiedliches tun, aber immer zusammen passen müssen. Bietet sich also an, das zu automatisieren, denn von Hand ist schon von vorne herein klar, dass das irgendwann mal nicht passt. >> Frage ncht gelesen? Oder kannst du erklären, wie man das gleichzeitig in >> zwei verschiedenen Sprachen und auf zwei Systemen (von denen eins ein µC >> ist) verteilt nutzt? > > Zwei Systeme wären wohl kein Problem, Inwiefern? Es geht ja darum, enums, die auf einem der Systeme als Zahl ausgegeben werden, in einem anderen System in Strings zu wandeln. Ich wüßte nicht, wie der Code das bewerkstelligen könnte. Ich halte da ein Skript, das für beide Seiten den Code generiert, für am sinnvollsten und auch robustesten.
:
Bearbeitet durch User
Moin Moin, vielen Dank für eure ganzen Antworten! Was ich noch vergessen habe: Die Idee den Enums für beide Seiten zu generieren hatte ich schön - mein Problem ergibt sich grade aber daraus, das ich auch Enums aus externen libs in den Logdaten habe und deren Header sind halt schon da - die neu zu generieren macht ja wenig Sinn. Ob die sich bei einem Update der lib jemals ändern weiß ich zwar nicht - aber abschreiben und nachher fehlende (oder schlimmer geänderte) Werte zu haben ist mir da zu riskant... Ich werde mir nächste Woche mal den XML Export von doxygen und ctags ansehen. Die Reflektion Geschichten sind zwar kein echtes Problem - aber es ist halt doch etwas aufwändiger in der Umsetzung als einfach nur ein Tool über die entsprechenden Header laufen zu lassen. Viele Grüße Michael
Rolf M. schrieb: > Inwiefern? Es geht ja darum, enums, die auf einem der Systeme als Zahl > ausgegeben werden, in einem anderen System in Strings zu wandeln. Ich > wüßte nicht, wie der Code das bewerkstelligen könnte. Ich halte da ein > Skript, das für beide Seiten den Code generiert, für am sinnvollsten und > auch robustesten. So wie in jedem anderen cross-platform Code auch?
1 | void print(enum E e) { |
2 | #ifdef __x86_64__
|
3 | printf("%s\n", to_str(e)); |
4 | #else
|
5 | printf("%d\n", e); |
6 | #endif
|
7 | }
|
:
Bearbeitet durch User
Trotzdem hier noch ein Beispiel, wie es komplett in C geht:
1 | #include <assert.h> |
2 | |
3 | #include "map.h" |
4 | |
5 | #define DEF_ENUMSTR_I2(name,assign) case name: return #name; break;
|
6 | #define DEF_ENUMSTR_I(elem) EVAL0(DEF_ENUMSTR_I2 elem)
|
7 | |
8 | #define DEF_ENUM_I2(name,assign) name assign
|
9 | #define DEF_ENUM_I(elem) EVAL0(DEF_ENUM_I2 elem)
|
10 | #define DEF_ENUM(name,...) enum name { MAP_LIST(DEF_ENUM_I, ## __VA_ARGS__) }; const char* name##ToStr (enum name val) { switch (val) { MAP(DEF_ENUMSTR_I,## __VA_ARGS__ ) default: assert (0); return 0; break; } }
|
Die "map.h" Datei ist diese: https://github.com/swansontec/map-macro/blob/master/map.h Wenn obiger Code in einer "enunmstr.h" vorliegt, kann man das so nutzen:
1 | #include <stdio.h> |
2 | #include "enumstr.h" |
3 | |
4 | DEF_ENUM(Animals,(Cat,),(Dog,=3),(Mouse,=42)) |
5 | |
6 | void test (enum Animals a) { |
7 | puts (AnimalsToStr (a)); |
8 | }
|
9 | |
10 | int main () { |
11 | test (Cat); |
12 | test (Dog); |
13 | test (Mouse); |
14 | // test (100);
|
15 | }
|
Die Definitionssyntax ist nicht sehr schön, generiert aber ein normales enum und zusätzlich eine Funktion AnimalsToStr, welche aus einem "enum Animals" einen "const char*" macht. Auf dem uC braucht man die Funktion natürlich nicht; indem man sie einfach nie aufruft, wird sie wegoptimiert. Auf dem PC inkludiert man den selben Code und benutzt die Funktion um Strings zu generieren. Zusätzliche externe Tools zum (C-) Code Generieren sollten nur eine Notlösung sein; man hat immer das Problem dass diese unflexibel sind, sich nicht gut ins Buildsystem integrieren lassen, man Code auf dem kompilierenden System ausführen muss (bei Python o.ä. muss die runtime installiert sein, bei C braucht's einen Compiler für den Host). Insbesondere ist der generierte Code fix, es können keine Daten in die Code-Erzeugung eingeschleust werden; durch den Compiler generierter Code kann sich auf andere Makros o.ä. beziehen.
Moin Moin, also ich möchte euch meine Lösung nicht vorenthalten... doxygen und ctags extrahieren zwar hervorragend die enums, aber leider muss ich sie dann immernoch selbst hoch zählen. Daher bin ich wirklich auf Qt und die QMetaEnum Klasse gegangen. Ich includiere die Header mit den Enums jetzt in eine Klasse (wirklich mitten drin) schreibe da den Q_ENUM Kram drunter und generiere eine Funktion die dann über alle Enums iteriert. Testcode:
1 | QMetaEnum metaEnum = QMetaEnum::fromType<MyTestEnum>(); |
2 | for(int i=0; i<metaEnum.keyCount(); ++i) |
3 | { |
4 | const char* name = metaEnum.key(i); |
5 | int value = metaEnum.value(i); |
6 | |
7 | qDebug() << "Name[" << name << "] = Value[" << value << "]"; |
8 | } |
Vielen Dank für eure Tipps!! Viele Grüße Michael
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.