Ich habe versucht, mit der Preprocessor-Lib die Konstanten für eine Baudratentabelle mit 5 Einträgen mit jeweils 2 enum-Konstanten pro Baudrate (Teiler und 2x-Modus) zu generieren. Leider klappt das nicht, vermutlich, weil der Preprocessor anfängt, Unsinn zu machen, wenn das Ergebnis der Macrosubstitutionen 500 kB überschreitet. Symptom sind ellenlange Textwürmer aus konkatenierten Macronamen in der .i-Ausgabe - Macronamen dürfen im Ergebnis des Preprozessors nicht mehr vorkommen, zumindest wenn alle erforderlichen Header includet sind. Außerdem unsinnige Fehlermeldungen über ungültige Preprocessor-Tokens bestehend aus einem Macronamen und '(' oder ')' Eine interne Fehlermeldung des Preprozessors kommt nicht.
:
Bearbeitet durch User
Uhu U. schrieb: > Symptom sind ellenlange Textwürmer aus konkatenierten Macronamen in der > .i-Ausgabe - Macronamen dürfen im Ergebnis des Preprozessors nicht mehr > vorkommen, zumindest wenn alle erforderlichen Header includet sind. Das stimmt nicht ganz, wenn gültige Makro Aufrufe erst nach Substitution anderer Makros entstehen bleiben die unevaluiert, es sei denn man fügt einen extra Evaluations Level hinzu. So etwas mit dem Preprocessor zu machen ist enorm fummelig, versuche es vielleicht lieber mit C++ constexpr Funktionen oder templates, das kann viel einfacher sein (aber genauso effizient da vom Compiler berechnet)... Aber es ist mir aus deinem Code auch nicht ganz klar was du da berechnen möchtest.
Dr. Sommer schrieb: > Aber es ist mir aus deinem Code auch nicht ganz klar was > du da berechnen möchtest. Es sind 10 enum-Konstante, die damit definiert werden sollen, aber das ist im Prinzip egal - Kern der Sache ist, dass es den cpp aus den Latschen haut, wenn das Ergebnis zu groß wird. > Das stimmt nicht ganz, wenn gültige Makro Aufrufe erst nach Substitution > anderer Makros entstehen bleiben die unevaluiert, es sei denn man fügt > einen extra Evaluations Level hinzu. Das ist hier nicht der Fall und es wäre auch nicht sehr sinnvoll, Macroaufrufe zu gerieren, die dann unevaluiert dem Compiler zum Fraß vorgeworfen werden. > So etwas mit dem Preprocessor zu machen ist enorm fummelig... Mit der Boost.preprocessor nicht, wenn man das Prinzip, nach dem sie arbeitet, mal verstanden hat.
:
Bearbeitet durch User
Uhu U. schrieb: > Kern der Sache ist, dass es den cpp aus den > Latschen haut, wenn das Ergebnis zu groß wird. Da wäre ich mir nicht so sicher. Der CPP ist ziemlich alt und stabil. Es ist hingegen sehr einfach, ihn falsch zu verwenden, was bei dir der Fall sein könnte. Der CPP wurde niemals für Iterationen und dergleichen entwickelt. Die Iterationstiefe in Boost.PP ist ja auch begrenzt. Wenn du die überschreitest passiert Unfug. Uhu U. schrieb: > Das ist hier nicht der Fall In Boost.PP intern ist das ziemlich sicher der Fall und es kann gut sein dass das durch falsche Aufrufe getriggert wird. > und es wäre auch nicht sehr sinnvoll, > Macroaufrufe zu gerieren, die dann unevaluiert dem Compiler zum Fraß > vorgeworfen werden. Es ist auch nicht sinnvoll Nullpointer zu dereferenzieren, trotzdem machen das die Leute... Uhu U. schrieb: > Mit der Boost.preprocessor nicht, wenn man das Prinzip, nach dem sie > arbeitet, mal verstanden hat. Okay dann hast du da andere Erfahrungen gemacht. Nun, wenn du dir so sicher bist dass der Fehler im GCC liegt, kann dir hier vermutlich auch keiner helfen. Nun gut, du hast ja auch keine konkrete Frage gestellt.
PS: Man beachte: http://www.boost.org/doc/libs/1_63_0/libs/preprocessor/doc/ref/div.html "Valid values range from 0 to BOOST_PP_LIMIT_MAG." http://www.boost.org/doc/libs/1_63_0/libs/preprocessor/doc/ref/limit_mag.html "The BOOST_PP_LIMIT_MAG macro defines the maximum input and result agnitudes of arithmetic. [...] This macro currently expands to 256." Da deine Zahlen aber größer als 256 sind, funktionieren die Boost-Arithmetik-Funktionen nicht. Selbst diese simple Evaluierung funktioniert schon nicht, da brauchst du deinen ganzen Makro-Wurst gar nicht:
1 | int i5 = BOOST_PP_ADD(8000000, 8); |
Hat also nichts mit dem GCC zu tun, CPP und Boost.PP sind einfach für so etwas nicht gemacht. Mit constexpr Funktionen/templates hast du dieses Problem nicht...
Dr. Sommer schrieb: > Da deine Zahlen aber größer als 256 sind, funktionieren die > Boost-Arithmetik-Funktionen nicht. Oh ja... Das degradiert die Lib zum Spielzeug. Selbst BOOST_PP_LIMIT_MAG auf 115200 hoch zu setzen, wird wenig bringen, weil der cpp dann Stunden brauchen wird, das alles zusammenzufrickeln. Ich habe mal etwas ausgiebiger mit m4 rumgespielt - der ist nicht ganz so doof, wie der cpp, aber etwas kompliziertere Macros produzieren auch dort einen immensen Aufwand und gehörige Laufzeiten.
Uhu U. schrieb: > Oh ja... Das degradiert die Lib zum Spielzeug. Nicht alles, was nicht deinen Zwecken entspricht, ist ein Spielzeug. Die Boost.PP ist keine Numerik-Bibliothek. Man muss halt seine Werkzeuge sinnvoll auswählen.
Die Arithmetik-Macros muss man nicht in Boost implementieren - da reichen ganz normale cpp-Macros. Das Ergebnis kann man dann mit Boost-Textmacros zu den gewünschten Strukturen zusammenbasteln. Etwas mysteriös ist eine Warnung "large integer implicitly truncated to unsigned type [-Woverflow]|" beim Erzeugen der Datenstruktur (Zeile 42 in uart-test.c) Versuche durch selektives Löschen von Teilausdrücken haben bisher nur ergeben, dass der Fehler mit dem ersten Wert (Bxxxx) im Initialisierer zusammenhängt; warum die Warnung nur einmal auftritt, verstehe ich nicht. (Im [zusammengestutzten] .i-File ist das Zeile 23.) Im Anhang die geänderten Quellen und das Ergebnis des cpp. Letztendlicher Witz der Sache ist, dass man mit einer einzigen Definition wie
1 | #define BAUDRATES (4800)(9600)(19200)(38400)(57600)(115200)
|
eine passende Tabelle mit den Einstellungsdaten für den UART und einen String mit der Baudrate generieren kann:
1 | const __flash BaudRate Bdrate[] = { |
2 | { B4800, B4800_2X, "4800" }, |
3 | { B9600, B9600_2X, "9600" }, |
4 | { B19200, B19200_2X, "19200" }, |
5 | { B38400, B38400_2X, "38400" }, |
6 | { B57600, B57600_2X, "57600" }, |
7 | { B115200, B115200_2X, "115200" }, |
8 | };
|
Die Symbole Bxxxx und Bxxxx_2X sind enum-Konstanten, die die eigentlichen Werte definieren. Die Enumeration wird als Zwischenschritt erzeugt, der generierte Text ist - wie man in .i sieht - etwas unübersichtlich...
:
Bearbeitet durch User
Uhu U. schrieb: > Die Arithmetik-Macros muss man nicht in Boost implementieren - da > reichen ganz normale cpp-Macros. > > Das Ergebnis kann man dann mit Boost-Textmacros zu den gewünschten > Strukturen zusammenbasteln. > > Etwas mysteriös ist eine Warnung > "large integer implicitly truncated to unsigned type [-Woverflow]|" > beim Erzeugen der Datenstruktur (Zeile 42 in uart-test.c) Verwende unsigned Konstanten. > Versuche durch selektives Löschen von Teilausdrücken räusper soviel zu wartbarem Code :-) > Witz > const __flash BaudRate Bdrate[] = { > { B4800, B4800_2X, "4800" }, > { B9600, B9600_2X, "9600" }, > { B19200, B19200_2X, "19200" }, > { B38400, B38400_2X, "38400" }, > { B57600, B57600_2X, "57600" }, > { B115200, B115200_2X, "115200" }, > }; Und dafür brauch man Boost?
Ich habe mal deinen Quellcode überarbeitet, um ein Lösung mit C++11 constexpr zu zeigen, wenn dies vom Compiler unterstützt wird. Im Prinzip ist es nichts anderes als die Macros, nur dass der Compiler bessere Meldungen erzeugen kann und die Boost Header mit den Macros für die Berechnung nicht mehr nötig sind. Ich habe angenommen, dass die enum Konstanten (B4800, B4800_2X) im weiteren Code nicht verwendet werden und nur für die Befüllung der Tabelle nötig waren. Zur Erklärung: In setbaud.h habe ich die Makros durch Funktionen mit constexpr ersetzt. Damit ist auch direkt ersichtlich, welcher Datentyp von der Funktion erwartet wird und zurückgegeben werden soll. Die Warnings mit truncated Integern würden dann direkt in der entsprechenden Funktion gemeldet und nicht erst, wenn das ganze expandierte Makro ausgewertet wird. Das constexpr garantiert, dass die Funktion zur Compilezeit ausgewertet werden kann, wenn sie mit Konstanten Argumenten aufgerufen wird. Im Prinzip ginge es auch mit C Mitteln ohne constexpr, dann müsste man sich aber auf die Optimierung des Compilers verlassen, dass die Berechnungen zur Compilezeit stattfinden.
M.K. B. schrieb: > Ich habe mal deinen Quellcode überarbeitet, um ein Lösung mit C++11 > constexpr zu zeigen, Fehlen nur noch Kleinigkeiten wie __flash :-)
Johann L. schrieb: > Fehlen nur noch Kleinigkeiten wie __flash :-) Da hast du Recht. Ich muss zugeben, dass ich das gerade nur auf einem Desktop Linux mit gcc ausprobiert habe. Aber __flash legt doch nur fest, dass die Konstanten später im Flashspeicher landen. Wie der Compiler die Konstanten bestimmt sollte davon eigentlich unabhängig sein. Ob das der entsprechende Embedded Compiler aber auch so sieht, weiß man nicht. :-D
M.K. B. schrieb: > Johann L. schrieb: >> Fehlen nur noch Kleinigkeiten wie __flash :-) > > Da hast du Recht. Ich muss zugeben, dass ich das gerade nur auf einem > Desktop Linux mit gcc ausprobiert habe. > > Aber __flash legt doch nur fest, dass die Konstanten später im > Flashspeicher landen. Nö, es wird auch anders auf die Daten zugegriffen (im Gegensatz zu progmem).
Uhu U. schrieb: > Dr. Sommer schrieb: >> Da deine Zahlen aber größer als 256 sind, funktionieren die >> Boost-Arithmetik-Funktionen nicht. > > Oh ja... Das degradiert die Lib zum Spielzeug. Arithmetik mit Integer-Zahlen >256 und FP-Zahlen kann der Compiler, dazu muss man nicht den Präprozessor vergewaltigen. Aber das hast du ja mittlerweile selber herausgefunden. Uhu U. schrieb: > Wie kann man mit Boost eine Sequenz (1)(2)(3)... aufsummieren? Indem man zuerst die Dokumentation liest und danach passend dazu den Code hinschreibt:
1 | #include <boost/preprocessor.hpp> |
2 | |
3 | #define SEQ (1)(2)(3)
|
4 | |
5 | #define OP(s, state, x) BOOST_PP_ADD(state, x)
|
6 | #define SUM BOOST_PP_SEQ_FOLD_LEFT(OP, 0, SEQ)
|
7 | |
8 | SUM
|
Test:
1 | $ cpp pctest.c | grep -v '^\(#\s*[0-9]\|$\)' |
2 | 6 |
Yalu X. schrieb: > Arithmetik mit Integer-Zahlen >256 und FP-Zahlen kann der Compiler, dazu > muss man nicht den Präprozessor vergewaltigen. Kommt darauf an, was man damit machen will... Die Arithmetik von PP braucht man zum Glück nur für Werte, die den Ablauf der Lib betreffen. Ausdrücke, mit denen der Compiler oder der cpp außerhalb von PP was machen sollen, kann man so hinschreiben. Für die Konfiguration von Quelltextbibliotheken ist PP auf jeden Fall eine Option, wenn man nur c zur Verfügung hat.
Uhu U. schrieb: > Kommt darauf an, was man damit machen will... Die Arithmetik von PP > braucht man zum Glück nur für Werte, die den Ablauf der Lib betreffen. Eben. Und dafür reichen i.Allg. auch kleine Zahlenwerte. In deinem Beispiel vom 04.01.2017 17:20 würdest erst an eine Grenze stoßen, wenn du mit mehr als 256 unterschiedlichen Bauraten hantieren wolltest. Auch für das Aufsummieren der Elemente einer Boost-PP-Sequenz kann man den Compiler zuhilfe nehmen und ist dann nicht durch die Boost-PP-Limits beschränkt:
1 | #include <boost/preprocessor.hpp> |
2 | |
3 | #define SEQ (1123.4)(765.9)(83734.1)
|
4 | |
5 | #define OP(s, state, x) state+x
|
6 | #define SUM BOOST_PP_SEQ_FOLD_LEFT(OP, 0, SEQ)
|
7 | |
8 | SUM
|
Test:
1 | $ cpp pctest.c |grep -v '^\(#\s*[0-9]\|$\)' |
2 | 0 +1123.4 +765.9 +83734.1 |
Diese Summe berechnet der Compiler, so dass zur Laufzeit dafür keine Rechenzeit verbraucht wird. Nur kann das Ergebnis eben nicht mehr im Präprozessor verwendet werden.
:
Bearbeitet durch Moderator
Yalu X. schrieb: > Diese Summe berechnet der Compiler, so dass zur Laufzeit dafür keine > Rechenzeit verbraucht wird. Rechnen kann der cpp eben nicht selber... nur mit Texten jonglieren.
Und hier die funktionsfähige Baudratentabelle - siehe Anhang. uart.c: In Zeile 20 wird die zulässige Baudraten-Toleranz definiert. In Zeile 23 werden die die gewünschten Baudraten als Boost-Sequenz definiert. In Zeile 28 werden die Baudratengenerierungsparameter für einen ATmega 328 in Form von emum-Konstanten berechnet. In Zeile 30 wird geprüft, ob einzelne Baudraten die Toleranz überschreiten. In Zeile 38 werden die Initialisierungen eines Arrays vom Typ struct BaudRate (am Ende von setbaud.h definiert) berechnet. In Zeile 41 werden die Macrodefinitionen für die ganze Übung entsorgt. Die Boost-Header-Includes könnte man auch noch in setbaud.h verschwinden lassen... Der Headerfile setbaud.h enthält die ganze Boost-Definition - man muss ihn nicht mehr anfassen... Die (Zwischen-)Ergebnisse für 2 Taktfrequenzen sind im letzten Anhang aufgelistet.
:
Bearbeitet durch User
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.