if (baud==300 || baud==600 || baud==1200 || baud==2400 || baud==4800 || baud==9600 || baud==14400 || baud==19200 || baud==28800 || baud==38400 || baud==57600 || baud==115200 || baud==230400) { } kann man das auch anders schreiben? Irgendwie so ähnlich wie in switch/case, da gibts ja auch eine Liste von Argumenten: case 300: case 600: etc Am erzeugten Code wird sich ja eher nichts ändern - mir gefällt das so einfach nicht besonders :-)
switch (baud) { case 300: case 600: case 1200: case 2400: case 4800: case 9600: case 14400: case 19200: case 28800: case 38400: case 57600: case 115200: case 230400: // entspricht if() Zweig break; default: // entspricht else Zweig break; } Gruß, Stefan
1 | switch(baud) { |
2 | case 300: |
3 | case 600: |
4 | case 1200: |
5 | ...
|
6 | }
|
wäre eine Möglichkeit. Grüsse, René
Schöner und einfacher zu erweitern ist ja die Suche in einem Array:
1 | #include <iostream> |
2 | #include <cstdint> |
3 | #include <algorithm> |
4 | #include <array> |
5 | |
6 | |
7 | // Variante 1
|
8 | bool isbaud1 (uint32_t baud) { |
9 | static const uint32_t baudrates [] = |
10 | { 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, 115200, 230400 }; |
11 | |
12 | return std::any_of (baudrates, baudrates + (sizeof(baudrates) / sizeof (baudrates [0])), |
13 | [&](uint32_t x) { return x == baud; }); |
14 | }
|
15 | |
16 | // Variante 2
|
17 | bool isbaud2 (uint32_t baud) { |
18 | static const std::array<uint32_t,13> baudrates |
19 | {{ 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, 115200, 230400 }}; |
20 | |
21 | return std::find (baudrates.begin (), baudrates.end (), baud) != baudrates.end (); |
22 | }
|
23 | |
24 | // Nur zum Testen:
|
25 | int main () { |
26 | uint32_t testbaud [] = { 300, 42, 14400, 230400 }; |
27 | |
28 | std::cout << "Variante 1: "; |
29 | for (auto b : testbaud) |
30 | std::cout << b << " => " << std::boolalpha << isbaud1 (b) << ", "; |
31 | std::cout << std::endl; |
32 | |
33 | std::cout << "Variante 2: "; |
34 | for (auto b : testbaud) |
35 | std::cout << b << " => " << std::boolalpha << isbaud2 (b) << ", "; |
36 | std::cout << std::endl; |
37 | |
38 | return 0; |
39 | }
|
Somit lässt sich die Liste leichter verändern, und man kann einen Schleifenalgorithmus zum Suchen nutzen.
Dr. Sommer schrieb: > Schöner und einfacher zu erweitern ist ja die Suche in einem Array: Wir sind hier in dem Unterforum Mikrocontroller. Auf einem Mikrocontroller will man keine stdlib einsetzen. Grüsse, René
Rene H. schrieb: > Wir sind hier in dem Unterforum Mikrocontroller. Auf einem > Mikrocontroller will man keine stdlib einsetzen. Warum will man das nicht? Ich mache das jeden Tag.
Dr. Sommer schrieb: > Rene H. schrieb: >> Wir sind hier in dem Unterforum Mikrocontroller. Auf einem >> Mikrocontroller will man keine stdlib einsetzen. > Warum will man das nicht? Ich mache das jeden Tag. Ok, das erstaunt mich jetzt. Ich kenne die stdlib so, dass sie ziemlich viel unnötigen Speicher verbraucht. Aber ich werde das gerne mal auf einem Mikrocontroller testen. Grüsse, René
Rene H. schrieb: > Ok, das erstaunt mich jetzt. Ich kenne die stdlib so, dass sie ziemlich > viel unnötigen Speicher verbraucht. Das ist Quatsch. Rene H. schrieb: > Aber ich werde das gerne mal auf einem Mikrocontroller testen. Gerne. Im Anhang das Kompilat obigen Codes für Cortex-M4. Wie zu sehen ist, hat sich der Compiler hier dazu entschieden die Schleife zur Erhöhung der Performance auszurollen. Aber es kein überhaupt keinen "unnötigen Speicherverbrauch".
Ich finde den Vorschlag von Dr. Sommer eine interessante Lösung. Für ein paar Baudraten vielleicht etwas oversized. Aber spätestens wenn die Liste der Vergleiche größer wird, wird das sehr interessant. Und das .s Beispiel zeigt eindrucksvoll, wie flexibel der Compiler da optimieren kann. Gruß, Stefan P.S.: Die negativen Bewertungen für Dr. Sommers Beiträge kann ich mir nur mit ideologischen Scheuklappen erklären.
Stefan K. schrieb: > Die negativen Bewertungen für Dr. Sommers Beiträge kann ich mir nur mit > ideologischen Scheuklappen erklären. Na, dem kann man doch entgegenwirken :-) +1 von mir auf alle Fälle.
Ist switch (baud) { if (baud==300 || case 300: baud==600 || case 600: baud==1200 || case 1200: baud==2400 || case 2400: baud==4800 || case 4800: baud==9600 || case 9600: baud==14400 || case 14400: baud==19200 || case 19200: baud==28800 || case 28800: baud==38400 || case 38400: baud==57600 || case 57600: baud==115200 || case 115200: baud==230400) case 230400: { break; } else default: { } } da wirklich ein Unterschied? Natürlich war die Ausgangsformulierung eher mittelprächtig, kompakt, aber kaum lesbar.
Amateur schrieb: > da wirklich ein Unterschied? Vom Resultat (also Kompilat) nicht, nein. Nur besser lesbar. Grüsse, René
Ein + an Dr. Sommer! Ich habe mit C++ auf embedded systemen nur positive Erfahrung (wenn man weiss was man tut... aber das ist bei C auch so...) Zum Besänftigen aller C Puristen noch eine Variante, die in C und C++ läuft:
1 | bool isbaud(uint32_t baud) |
2 | {
|
3 | static const uint32_t baudrates[] = |
4 | { 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, 115200, 230400, 0}; //Beachte Arrayabschluss mit 0 |
5 | size_t i = 0; |
6 | while (baudrates[i]) |
7 | {
|
8 | if (baudrates[i] == baud) return true; |
9 | i++; |
10 | }
|
11 | |
12 | return false; |
13 | }
|
Marc schrieb: > Zum Besänftigen aller C Puristen noch eine Variante, die in C und C++ > läuft: Na hoffentlich muss man das Schema nie auf etwas übertragen, wo eine 0 im Array stehen kann! Da ist eine schlichte for-Schleife doch einfacher:
1 | #include <stdbool.h> |
2 | #include <stdint.h> |
3 | #include <stddef.h> |
4 | |
5 | bool isbaud (uint32_t baud) { |
6 | static const uint32_t baudrates[] = |
7 | { 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, 115200, 230400}; |
8 | static const size_t length = sizeof (baudrates) / sizeof (baudrates [0]); |
9 | for (size_t i = 0; i < length; ++i) |
10 | if (baudrates [i] == baud) |
11 | return true; |
12 | return false; |
13 | }
|
Solche Konstrukte nach Schema F können Compiler typischerweise auch besser optimieren...
@ Dr. Sommer (Gast) > for (size_t i = 0; i < length; ++i) > if (baudrates [i] == baud) > return true; > return false; Ein "schönes" Beispiel, wie man in C NICHT programmieren sollte! Bei Schleifen, if(), switch() etc. IMMER Klammern setzen! Dann gibt es auch keine bösen Überraschungen und die Struktur ist besser lesbar sowie besser erweiterbar!
Falk B. schrieb: > Ein "schönes" Beispiel, wie man in C NICHT programmieren sollte! Bei > Schleifen, if(), switch() etc. IMMER Klammern setzen! Das ist jetzt sehr dogmatisch. Wenn man einen vernünftigen Editor verwendet und immer schön einrückt, ist das halb so schlimm, dafür kompakter. Aber um Klammern ging es eigentlich gar nicht...
Falk B. schrieb: > Ein "schönes" Beispiel, wie man in C NICHT programmieren sollte! Dann hättest du aber eher anmerken sollen, dass man UINT32_C benutzen soll. Vorallem auf dem Mikrocontroller...
Gerhard schrieb: > kann man das auch anders schreiben? Ja, natürlich kann man sowas ganz anders schreiben und auch MACHEN. Also Kopf mal aus der Furche erheben und ne wirklich bessere Lösung praktizieren. Normalerweise hat man ja seinen zuständigen Systemtakt und man hat einen Baudratengenerator im UART-Core enthalten, den man einstellen muß. Anstatt sich eine Latte von Standard-Baudraten mit if(xyz)... zu programmieren und dann die Einstellwerte aus ner Tabelle oder so zu entnehmen, kann man die Registerwerte für den Baudratengenerator auch (Überraschung!...) errechnen. Das kostet in den meisten Fällen nicht mehr an Code als eine Latte von if..else und ist deutlich flexibler. Ich mache das immer so bei den UART-Standardcores, die in den LPCxxxx verbaut sind - und da die Dinger nen fraktionalen BRG enthalten, kommt man selbst bei exotischen Baudraten damit hin. Also nicht "wie kann ich eine stupide Methode besser schreiben", sondern "wie kann ich eine bessere Methode schreiben". W.S.
W.S. schrieb: > Normalerweise hat man ja seinen zuständigen Systemtakt und man hat einen > Baudratengenerator im UART-Core enthalten, den man einstellen muß. > > Anstatt sich eine Latte von Standard-Baudraten mit if(xyz)... zu > programmieren und dann die Einstellwerte aus ner Tabelle oder so zu > entnehmen, kann man die Registerwerte für den Baudratengenerator auch > (Überraschung!...) errechnen. Das kostet in den meisten Fällen nicht > mehr an Code als eine Latte von if..else und ist deutlich flexibler. wo steht denn das der TO den Baudratengenerator einstellen will? Kann man zwar erraten, aber (falsche) Annahmen sind oft der erste Fehler. Vielleicht hat er was ganz anderes im Sinn und da ist Rechnen wirklich nicht angesagt.
Vielen Dank schon mal für die rege Beteiligung. Da werde ich mich gleich mal durchforsten. @W.S. Setzen, 6. Du hast da Sachen reininterpretiert, die gar zur Diskussion standen. Konkret gehts darum, die UART1 vom Anwender zur Laufzeit einzustellen. Und das soll eben nur gemacht werden können, wenn korrekte und vorgesehene Parameter geschickt werden. "9600,8N1" wird akzeptiert, eingestellt und bestätigt. 19300 eben nicht. Ausserdem hatte ich so ein Problem schon mal in einem anderen Zusammenhang.
Wenn man Code sparen will, kann man das auch berechnen:
1 | bool isbaud (uint32_t baud){ |
2 | for( ; !(baud & 1); baud >>= 1 ){ |
3 | switch( baud ){ |
4 | case 300: |
5 | case 14400: return 1; |
6 | case 76800: |
7 | case 460800: return 0; |
8 | }
|
9 | }
|
10 | return 0; |
11 | }
|
> Na hoffentlich muss man das Schema nie auf etwas übertragen, wo eine 0 > im Array stehen kann! Da ist eine schlichte for-Schleife doch > einfacher Die Variante mit for.... habe ich natürlich auch, aber ich dachte das ist jetzt zu langweilig. Die 0 Terminierung hat auch Vorteile, z.B. muss die Arraygröße nicht bekannt sein. Sehr interessant, wenn zur Laufzeit unterschiedliche Listen genutzt werden... Jetzt musst du mir erklären weshalb diese Variante "einfacher" sein soll als eine for Schleife. Wird eine for Schleife tatsächlich besser optimiert als die Wert-Terminierung? Falk B. schrieb: > Ein "schönes" Beispiel, wie man in C NICHT programmieren sollte! Bei > Schleifen, if(), switch() etc. IMMER Klammern setzen! Dafür hab ich AStyle benutzt um die Einrückung korrekt zu machen, Ätsch. Spass beiseite: du hast recht, eigentlich sollte man sich angewöhnen immer Klammern zu nutzen. Aber es ist korrekter C Code...
Nase schrieb: > > Dann hättest du aber eher anmerken sollen, dass man UINT32_C benutzen > soll. Vorallem auf dem Mikrocontroller... Ich verstehe den Kontext nicht. Kannst Du das näher erklären?
Marc schrieb: > Sehr interessant, wenn zur Laufzeit > unterschiedliche Listen genutzt werden... Da würde ich doch lieber die Länge seperat mit übergeben, genauso wie std::vector in C++ es im Endeffekt auch macht. Da gibts dann keine Kopfschmerzen wenn man doch mal eine 0 braucht. Dinge mit 0 zu terminieren ist so eine C-Unsitte... Marc schrieb: > Jetzt musst du mir erklären weshalb diese Variante "einfacher" sein soll > als eine for Schleife. Hauptsächlich weil man auf einen Blick sieht, wie oft die Schleife durchläuft, wie der Schleifenzähler sich ändert und so. Das 0815-Schema hilft einfach dabei, die Schleife sofort zu verstehen. Bei der while-Schleife muss man erst den Schleifenkörper und die 0 suchen um das zu erfassen. Marc schrieb: > Wird eine for Schleife tatsächlich besser > optimiert als die Wert-Terminierung? Kann unter Umständen passieren, wenn der Compiler z.B. die Zählrichtung umkehrt weil auf manchen Plattformen der Vergleich mit 0 schneller ist. Ist aber stark vom Einzelfall abhängig.
Du hast mich noch nicht überzeugt... Ich kenne einige Codeteile, die solche Terminierungen nutzen. Nicht zuletzt arbeiten C Strings auch so.Wenn jemand die sizeof(array) / sizeof(array[0] Variante falsch nutzt geht es auch schief... Im Beispiel sind Array und Zugriffsmethode lokal beieinander, man erkennt den Bezug, zumal ich extra einen Kommentar eingefügt habe.
Dr. Sommer schrieb: > Kann unter Umständen passieren, wenn der Compiler z.B. die Zählrichtung > umkehrt weil auf manchen Plattformen der Vergleich mit 0 schneller ist. > Ist aber stark vom Einzelfall abhängig. und der Compiler kann den Code so weit analysieren dass er die Zählrichtung umdrehen darf? in em Beispiel mag es gehen, in den meisten anderen Schleifen aber nicht. Den Code deswegen "optimiert" zu schreiben ist in 99,9% der Fälle völlig unnötig. Und in den restlichen 0,1% macht man sich lieber Gedanken um den prinzipiellen Algorithmus
Marc schrieb: > Ich kenne einige Codeteile, die solche Terminierungen nutzen. Ja, da gibt es jede Menge von. Marc schrieb: > Nicht zuletzt arbeiten C Strings auch so. Ja, und das ist der Auslöser für diverse Bugs, die manchmal auch sicherheitskritisch sind (ich meine da gab es z.B. mal was in PHP)... Marc schrieb: > Wenn jemand die sizeof(array) / sizeof(array[0] Variante falsch nutzt > geht es auch schief... Deswegen kapselt man das mit entsprechenden Funktionen/Makros/struct's. In C++ geht das dann besser, wie in std::vector vorgemacht. Marc schrieb: > Im Beispiel sind Array und Zugriffsmethode lokal beieinander, man > erkennt den Bezug, zumal ich extra einen Kommentar eingefügt habe. Ja da geht's. Aber ich finde so etwas einfach hässlich, weil es nicht universell ist und nur ein "Workaround", um die Länge nicht immer explizit mit angeben zu müssen, weil das in C zu anstrengend ist.
Dr. Sommer schrieb: bool isbaud2 (uint32_t baud) { static const std::array<uint32_t,13> baudrates {{ 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, 115200, 230400 }}; return std::find (baudrates.begin (), baudrates.end (), baud) != baudrates.end (); } Amateur schrieb: if (baud==300 || baud==600 || baud==1200 || baud==2400 || baud==4800 || baud==9600 || baud==14400 || baud==19200 || baud==28800 || baud==38400 || baud==57600 || baud==115200 || baud==230400) { } else { } ich sehe in der zweiten Varianten auf einen Blick was gemacht wird und könnte sofort eine Änderung vornehmen, in der ersten Variante muss ich erst 3x hinschauen was da gemacht wird
Dr. Sommer schrieb: ... Gute Argumentation. Ich hätte diese Lösung auch nicht in jeder Applikation genutzt. Verstehst du was Nase meint? >Nase schrieb: >> Dann hättest du aber eher anmerken sollen, dass man UINT32_C benutzen soll. Vorallem auf dem Mikrocontroller...
Marc schrieb: > Verstehst du was Nase meint? Ich vermute er meint man solle uint32_t -Literale der Form UINT32_C(230400) schreiben, damit der Compiler garantiert den richtigen Typ erwischt, denn bei Literalen wird niemals von alleine etwas genommen das kleiner "int" ist. Das ist in diesem Fall aber unnötig, da durch den Array-Typ der Integer-Typ bereits vorgegeben ist. In C++ würde ich aber, falls es denn nötig ist, lieber uint32_t { 230400 } verwenden, denn das funktioniert garantiert mit allen Integer-Typen und aliasen, ohne dass man noch zu jedem Integer-Typ ein Makro bräuchte.
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.