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
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.
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
boolisbaud(uint32_tbaud)
2
{
3
staticconstuint32_tbaudrates[]=
4
{300,600,1200,2400,4800,9600,14400,19200,28800,38400,57600,115200,230400,0};//Beachte Arrayabschluss mit 0
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:
@ 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.
> 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.