Etitie schrieb:> Hier ist mein Code, welcher leider nicht funktioniert.
Was erwartest du und was tut sich stattdessen?
> Wo ist aber der Fehler?
Welche Fehlermeldung bekommst du denn wofür?
Etitie schrieb:> leider nicht funktioniert. Wo ist aber der Fehler?
Grundlagen von C(++).
if(befehl == "ein" fragt, ob die Speicheradresse des ersten Zeichens in
befehl identisch mit der Speicheradresse des ersten Zeichens des
konstanten Strings "ein" ist. Natürlich niemals.
Du brauchst eine Funktion wie strcmp oder befehl.compare
MaWin schrieb:> Du brauchst eine Funktion wie strcmp oder befehl.compare
Ich vermute mal, dass das ein C++ String ist und seit wann muss ich bei
C++-Strings strncmp verwenden?
Lothar M. schrieb:> Was erwartest du und was tut sich stattdessen?
Wenn ich "ein" eingebe, passiert garnichts.
Lothar M. schrieb:> Welche Fehlermeldung bekommst du denn wofür?
Keine.
MaWin schrieb:> Grundlagen von C(++).>> if(befehl == "ein" fragt, ob die Speicheradresse des ersten Zeichens in> befehl identisch mit der Speicheradresse des ersten Zeichens des> konstanten Strings "ein" ist. Natürlich niemals.> Du brauchst eine Funktion wie strcmp oder befehl.compare
Ich glaube Arduino ist einwenig anders als reines C++ und C. Das geht
das schon.
MaWin schrieb:> if(befehl == "ein" fragt, ob die Speicheradresse des ersten Zeichens in> befehl identisch mit der Speicheradresse des ersten Zeichens des> konstanten Strings "ein" ist.
Man könnte aber den "==" Operator so überladen, dass er so einen
Stringvergleich auch tatsächlich beherrscht. Oder wie war das mit dem ++
in C++? In VHDL mache ich sowas auf jeden Fall ständig... ;-)
Etitie schrieb:> Ich glaube Arduino ist einwenig anders als reines C++ und C.
Nicht so sehr, wie du es dir erträumst.
> Das geht das schon.
Ja, offenbar doch eher nicht. Oder wie jetzt?
Du musst also nachsehen, ob in der Stringklasse der Vergleich auf "=="
tatsächlich so implementiert ist, wie du es willst. So wie ich das sehe
ist das nämlich eine recht stupide Klasse:
https://www.arduino.cc/reference/de/language/variables/data-types/stringobject/
Von Vergleichsoperatoren ist da keine Rede....
Ben S. schrieb:> Ich denke eher, dass bei diesem mystischen und geheimen Code der Fehler> an anderer Stelle liegt.
Der Fehler liegt eher an der anderen Seite der seriellen Leitung. Er
muss ja ein "ein" ohne "\n" o.Ä. danach senden. Das können die meisten
Seriellen Terminalprogramme nicht, die warten auf die Enter-Taste.
Ich würde ein "befehl.trim()" nach dem readString empfehlen.
Hallo
Serial.avalable() geht schon beim ersten Zeichen in die if-Schleife.
Dann liest Du schon den ser Buffer aus. Im ungünstigsten Fall steht da
jetzt nur ein "e" drin. Das entspricht natürlich nicht dem "ein".
Lass die doch die Variable befehl einfach mal direkt nach dem befehl =
Serial.readString(); auf dem Monitor ausgeben.
Gruß Ulf
Geschafft schrieb:> Dann erkennst du was dein System rein bekommt...
Abzüglich irgendwelcher Steuerzeichen, die nicht übertragen werden.
Ulf L. schrieb:> Serial.avalable() geht schon beim ersten Zeichen in die if-Schleife.> Dann liest Du schon den ser Buffer aus. Im ungünstigsten Fall steht da> jetzt nur ein "e" drin.
Aber Serial.readString() wartet danach noch hardcoremäßig irgendein
Timeout ab:
https://www.arduino.cc/reference/de/language/functions/communication/serial/readstring/> Lass die doch die Variable befehl einfach mal direkt nach dem befehl => Serial.readString(); auf dem Monitor ausgeben.
Ja, so ein richtiger Debugger ist schon echtes Gold wert. Und dessen
Fehlen auch der Grund, warum ich diese Andruiden so ungern benutze. Da
artet das Debuggen immer gleich in eine Ratestunde aus und man muss mit
dem LA parallel nachmessen, was sich auf der Schnittstelle tut usw...
Εrnst B. schrieb:> Er muss ja ein "ein" ohne "\n" o.Ä. danach senden. Das können die> meisten Seriellen Terminalprogramme nicht, die warten auf die> Enter-Taste.
Mit dem "Seriellen Monitor" in der Andruiden-IDE kann man das auswählen:
https://learn.sparkfun.com/tutorials/terminal-basics/arduino-serial-monitor-windows-mac-linux
Ich nehme aber gern das alte OCConsole Terminal, das sendet einfach
jedes Zeichen genau dann, wenn ich es tippe... ;-)
Ulf L. schrieb:> Lass die doch die Variable befehl einfach mal direkt nach dem befehl => Serial.readString(); auf dem Monitor ausgeben.
Dann wird "ein" ausgegeben. Es wird immer das ausgegeben, was eingegeben
wurde. Mich wunderts nur, dass eine Neue Zeile dazwischen eingefügt
wird.
Etitie schrieb:> Mich wunderts nur, dass eine Neue Zeile dazwischen eingefügt> wird.
Eben. Mach statt dem println(befehl) ein
print("["); print(befehl); println("]");
dann siehst du, dass nicht nur "[ein]" sondern
"[ein
]"
rauskommt.
deshalb: befehl.trim().
Εrnst B. schrieb:> deshalb: befehl.trim().
Viel zu kompliziert.
Einfach das "\n" anhängen:
if(befehl == "ein\n"){
}else if(befehl == "aus\n"){
und schon läufts.
Sein Problem ist auch das es in der Arduino IDE einen definierten
String-Vergleich gibt: equalsIgnoreCase()
myString.equalsIgnoreCase(myString2)
Ohne GS/KS und: equals()
myString.equals(myString2)
mit GS/KS.
Wenn er diese Funktionen verwenden würde, wäre auch ein richtiges true
oder false für seine if/else Vergleiche vorhanden.
Vielleicht sollte der TO mal hier lesen:
https://www.arduino.cc/en/Tutorial/BuiltInExamples#strings
Mit freundlichen Grüßen EGS
Ich verstehe nicht warum Serial.readString(); die Steuerzeichen bekommt.
Das Terminal sendet die Eingabe erst nach (einem klick auf) send.
Anders wäre es, wenn jedes Zeichen einzeln live eingelesen würde.
Oder ist das ein Bug in der Arduino IDE?
Mister A. schrieb:> Ich verstehe nicht warum Serial.readString(); die Steuerzeichen bekommt.> Das Terminal sendet die Eingabe erst nach (einem klick auf) send.
Das Terminal sendet den String mit Sicherheit einschließlich einem
abschließenden Zeilenumbruch. Bei den meisten Terminalprogrammen kann
man einstellen ob und womit die Zeilen abgeschlossen werden sollen.
Schön, dass man Dir helfen konnte.
Hier die Anleitung zur Selbsthilfe, wenn sowas wieder auftritt:
Ich hätte auch geraten, die Eingabe im Sketch erstmal probehalber
auszugeben.
Das print("["); print(befehl); println("]"); geht auch - nunja, - ich
hätte in einer for-Schleife die Länge des Eingabestrings und die
Ascii-Codes jedes enthaltenen Zeiches ausgegeben.
Dann sieht man gseht genau, was eigentlich passiert.
hase
Frank schrieb:> Viel zu kompliziert.> Einfach das "\n" anhängen:> if(befehl == "ein\n"){> }else if(befehl == "aus\n"){> und schon läufts.
Wenn Du Pech hast, kommt da aber "ein\r" oder "ein\r\n" zurück. Man
sollte da schon so flexibel sein, dass man beliebige Whitespaces
abschneidet. Dafür bietet sich trim() in einfachster Form an. Oder man
schreibt etwas eigenes, denn trim() hat die Unart, auch "echte Spaces"
(Leerzeichen) abzuschneiden, was unter Umständen auch unerwünscht sein
kann.
Sein Problem ist das er bisher auf Systeme programmiert hat, die
Speicher satt haben.
"Ein" und "aus" als String in einen Arduino das ist gruselig.
Das macht man via True / False als Boolean.
Der Grund ist einfach. Du verbrauchst wertvollen Speicherplatz.
Wenn ich meine VB-Programme entwickele mache ich es manchmal genauso.
Aber da sind mir 10 KB Programmcode/Variablenspeicher völlig egal. Da
geht es um die Übersicht und die Möglichkeit spätere Änderungen zu
machen ohne das Prg. neu zu schreiben.
In einen Arduino ist Speicher Mangelware. Da solltest du von Anfang an
lernen das so was Unsinn ist.
Davon abgesehen ist, wie du gelernt hast, Stringverarbeitung im Arduino
nicht gerade angenehm.
Außer das ich Daten erstelle muss (für eine SD-Karte) kenne ich keine
Anwendung die Strings braucht. Ausgaben an ein Display gehen auch ohne.
Einfach den String als Text senden und gut ist. Deshalb kann man bei
alles Displays die ich kenne die Position genau bestimmen. Wenn man den
Text mit Leerzeichen auffüllt, wird auch ein möglicher alter Überhang
gelöscht. ;)
Kleiner Tipp. Schau mal beim Compilieren / Erstellen des Codes unten
hin. Dann siehst du was du an Speicher von wie viel Speicher
verbrauchst. Und 2 -3 Libs dazu und schon hast du ein großes Problem und
fragst wie man Libs "Kürzen" kann ;)
aber das Ende sollte schon erkannt werden
if(incomingByte == 13) oder if(incomingByte == '/r')
nur kommt das i.d.R. nicht in den "String" also
manuell die 0 einsetzen zur Weiterverarbeitung
Karl K. schrieb im Beitrag #6383637:
> Und dann werden die ganzen Strings noch im RAM> vorgehalten, statt sie aus dem Flash zu holen.
wo denn?
der der eingelesen wird muss ins RAM
der mit dem verglichen wird ist im flash
falls noch einer kommt:
OK du vermisst wohl:
else if( strstr_P(serial_in_command, PSTR("hell")) )
keine Sorge, ist drin, habe nur ein altes Beispiel gezeigt, der TO darf
auch noch lernen
Schlaumaier schrieb:> In einen Arduino ist Speicher Mangelware.
Noch nie einen Arduino in der Hand gehabt?
Die gibts mittlerweile mit richtig viel Speicher; da kommts auf einige
100kB nicht mehr an...
Frank schrieb:> Noch nie einen Arduino in der Hand gehabt?> Die gibts mittlerweile mit richtig viel Speicher; da kommts auf einige> 100kB nicht mehr an...
zu dem bemängeltem Code war vom ESP der 512k SRAM hat
deswegen fehlte auch strcmp_P und PSTR()
Joachim B. schrieb:> } // if !(chr_cnt<(MAXBUFFER-2))> } // if(isprint(incomingByte))> } // if !(incomingByte == 13)> } // while (Serial.available())
Wenn man Kommentare dieser Art braucht, um nicht den Überblick zu
verlieren, sollte man die Verschachtelung verringern.
Joachim B. schrieb:> if(incomingByte == 13) { // Wenn das Enter ankommt
Warum die 13 und nicht '\r'? Du ja auch '\0' statt 0. Bei der
Gelegenheit kannst du dann auch den fehlerhaften Kommentar in der Zeile
löschen.
Joachim B. schrieb:> else if( strstr_P(serial_in_command, PSTR("hell")) )>> keine Sorge, ist drin, habe nur ein altes Beispiel gezeigt, der TO darf> auch noch lernen
Bei so kurzen Strings spart man womöglich nicht einmal was, weil der
Zugriff auf den Flash aufwändiger ist, als RAM.
mh schrieb:> Warum die 13 und nicht '\r'?
nicht gelesen?
ist alter Code im Schnellzugriff, ich lerne auch immer dazu
Joachim B. schrieb:> aber das Ende sollte schon erkannt werden> if(incomingByte == 13) oder if(incomingByte == '/r')Stefan ⛄ F. schrieb:> Bei so kurzen Strings spart man womöglich nicht einmal was, weil der> Zugriff auf den Flash aufwändiger ist, als RAM.
auch das ist mir schon aufgefallen, aber trotzdem gab es ja einen
Kommentar und der wurde gelöscht!
Joachim B. schrieb:> Karl K. schrieb im Beitrag #6383637:>> Und dann werden die ganzen Strings noch im RAM>> vorgehalten, statt sie aus dem Flash zu holen.
aber ich prüfe ja wieviel Byte frei sind und kann entscheiden ob ich aus
dem flash lese mit strxxx_P PSTR() oder nicht!
Etitie schrieb:> if(befehl == "ein")Gerald K. schrieb:> Ich würde es mitif (strcmp(befehl,"ein") == 0)
Möchte noch jemand diesen falschen Hinweis geben?
strcmp() ist für C Zeichenketten vorgesehen, nicht für Arduino Strings,
das sind C++ Objekte. Die String Klasse hat den Operator ==
überscheieben, so dass Etite sie bereits korrekt angewendet hat.
Der Knackpunkt mit dem Zeilenumbruch wurde bereits geklärt.
Stefan ⛄ F. schrieb:> Möchte noch jemand diesen falschen Hinweis geben?
Ach, So ganz falsch ist das ja nicht, denn die Klasse verwendet
schließlich intern strcmp(), genau für diesen Zweck.
Also Thema korrekt erkannt, aber Kontext nicht verstanden.
> if (strcmp(befehl.c_str(),"ein") == 0)
würde sogar funktionieren.
(wenn nicht das EndlineChar Drama bestehen würde)
Innerhalb der Hauptschleife rufe ich wiederholt die Funktion
appendUntil() mit dem selben Puffer auf. Wenn der erwartete Terminator
(z.B. '\n') empfangen wurde, liefert die Funktion true zurück. Dann kann
ich die bis dahin empfangene Zeichenkette verarbeiten.
Der Terminator wird weg geschnitten.
Achtung: Der Puffer muss vor Aufruf der Funktion als Leerstring
initialisiert werden, als mit \0 beginnen.
Stefan ⛄ F. schrieb:> Achtung: Der Puffer
sollte optimal auch min 2 Byte größer sein um evtl. '/r' & '/n'
aufzunehmen
und gleichzeitig der Pufferüberlauf verhindert werden, wer weiss was so
alles kommen könnte!
Manchmal kommt auch Müll bei "Empfangsstörungen"
Die meiste Arbeit ist immer Fehler abzufangen.
dazu gehört auch das Zeichen auf isprint() zu prüfen
Stefan ⛄ F. schrieb:> Achtung: Der Puffer muss vor Aufruf der Funktion als Leerstring> initialisiert werden, also mit \0 beginnen.
Wobei das im obigen Fall automatisch passiert, weil buffer eine globale
Variable ist. Nach der Verarbeitung leert man ihn dann mit buffer[0]=0
so dass er für die nächste Eingabe bereit ist.
Mit der String Klasse habe ich mir zu oft den Heap fragmentiert, darum
verwende ich lieber eine offensichtlichere Speicherverwaltung, wo ich
sehe, was passiert.
Lothar M. schrieb:> Du musst also nachsehen, ob in der Stringklasse der Vergleich auf "=="> tatsächlich so implementiert ist, wie du es willst.> Von Vergleichsoperatoren ist da keine Rede....
Weil die Doku von Arduino unvollständig ist. Wenn man da wenigstens eine
ordentliche IDE hätte, die einen das hin und her Springen im
dokumentierten Quelltext ermöglichen würde, wäre das nur halb so wild.
Aber das fehlt da ja auch.
Ich benutze die IDE Qt Creator als "Externen Editor".
Arduino Fanboy D. schrieb:> Der geschickte Einsatz von String::reserve() mildert das Problem.
Der geschickte Einsatz einer Programmsprache, die Strings in der Länge
begrenzt, mindert das Problem enorm.
Beim Arduino gibts offenbar nichtmal eine Möglichkeit, die Buffergröße
für Serial einzustellen.
Stefan ⛄ F. schrieb:>> Ich würde es mitif (strcmp(befehl,"ein") == 0)> Möchte noch jemand diesen falschen Hinweis geben?
Ich werfe folgendes in den Raum:
if (strncmp(befehl.c_str(), "ein", 3) == 0) {...}
Das löst auch das Problem mit nachfolgenden Zeichen (und ja, als
Schönheitsfehler erkennt es "einander" auch als "ein").
S. R. schrieb:> Ich werfe folgendes in den Raum:> if (strncmp(befehl.c_str(), "ein", 3) == 0) {...}
Auch damit wechselst du zwischen C und C++., was unnötige Konvertierung
erfordert und den eigenen Quelltext schlechter lesbar macht.
Besser wäre in diesem Fall:
if (befehl.indexOf("ein")==0) {...}
Stefan ⛄ F. schrieb:> Auch damit wechselst du zwischen C und C++.,
Das passiert nur in deinem Kopf.
Stefan ⛄ F. schrieb:> was unnötige Konvertierung erfordert
Das passiert nur in deinem Kopf.
Stefan ⛄ F. schrieb:> und den eigenen Quelltext schlechter lesbar macht.
Naja, dem kann ich zustimmen.
Karl K. schrieb:> Der geschickte Einsatz einer Programmsprache, die Strings in der Länge> begrenzt, mindert das Problem enorm.
Wenn einem die originale String Klasse nicht passt, baut man sich eine
eigene, oder verwendet eine, welcher das gewünschte Feature auf dem
Schirm hat.
z.B. https://www.arduino.cc/reference/en/libraries/safestring/
Schwer vorstellbar, dass du damit überfordert bist.
Auch wird so ganz schnell klar, dass es kein Problem der
Programmiersprache ist....
Karl K. schrieb:> Beim Arduino gibts offenbar nichtmal eine Möglichkeit, die Buffergröße> für Serial einzustellen.
Eine Nebelkerze?
Denn mit dem Eingangsproblem hat das herzlich wenig zu tun.
Vielleicht ist die Einstellung nicht einfach erreichbar...
Aber dass es keine Möglichkeit gibt, ist schlicht falsch!
Schwer vorstellbar, dass du damit überfordert bist, den richtigen Ort zu
finden, und die Buffergröße nach Wunsch einzustellen.
Aber wenn dem wirklich so sein sollte, kann ich dir den Punkt gerne
zeigen.
Karl K. schrieb:> Beim Arduino gibts offenbar nichtmal eine Möglichkeit, die Buffergröße> für Serial einzustellen.
das ist falsch, es ist möglich aber nicht zielführend!
für MICH (wohlgemerkt) war es OK die Buffergröße für Serial zu
beizubehalten, in meinen Programmen einen eigenen Eingangsbuffer zu
definieren und etwas Platz zu lassen für CR und LF und zeichenweise
einzulesen, maximale Größe bestimmte ich nach den erwarteten Befehlen +2
und wenn ich 2 Byte unter der Länge war und kein CR oder LF kommt den
Buffer zu verwerfen und auf NULL zu setzen, sonst eben, als Terminator
wieder 0 am Ende anzuhängen.
Somit ist Weiterverarbeitung mit strxxx problemlos möglich.
Zu dem Code wäre noch anzumerken, dass auch readString() nicht ganz
unproblematisch ist, da diese Funktion – anders als istream::getline()
und std::operator>>(string) aus der Standardbibliothek – als einziges
Kriterium für das String-Ende einen Timeout (Default: 1 s) verwendet.
Sendet man den String mit einem gewöhnlichen Terminalprogramm, muss man
die Zeichen zügig eintippen, um zu vermeiden, dass der Timeout schon vor
dem Ende der Eingabe zuschlägt.
Beim Serial-Monitor der Arduino-IDE hat man dieses Problem nicht, da
dieser immer ganze Zeilen puffert. Aber auch hier muss man nach dem
Abschicken 1 s (oder was immer als Timeout eingestellt wurde) warten,
bis das Programm auf die Eingabe reagiert.
readStringUntil('\n') wäre hier evtl. die bessere Wahl, funktioniert
aber natürlich nur, wenn man im Terminal das Zeilendezeichen passend
eingestellt hat.
Stefan ⛄ F. schrieb:>> Von Vergleichsoperatoren ist da keine Rede....>> Weil die Doku von Arduino unvollständig ist.
Aber sicher ist das dokumentiert:
"The String comparison operators ==, !=,>, < ,>=, <= , and the equals()
and equalsIgnoreCase() methods allow you to make alphabetic comparisons
between Strings. They're useful for sorting and alphabetizing, among
other things."
https://www.arduino.cc/en/Tutorial/StringComparisonOperators
leo
Ich experimentierte auch mit malloc und free was aber den Speicher
fragmentiert, somit entschied ich mich für konstante kurze Buffer als
globale Variablen.
Eine Garbage Collection wie beim CBM fand ich nicht!
https://de.wikipedia.org/wiki/Garbage_Collection
Stefan ⛄ F. schrieb:> Auch damit wechselst du zwischen C und C++., was unnötige Konvertierung> erfordert und den eigenen Quelltext schlechter lesbar macht.
Da ein Arduino-String (wie auch std::string) ein ganz gewöhnlicher
C-String mit ein paar zusätzlichen Methoden ist, findet überhaupt keine
Konvertierung statt. Und was ich schrieb, sieht zwar wie C aus, ist aber
C++ - weil C++ (fast) ein Superset von C ist. Ob es besser lesbar oder
nicht, darüber lässt sich streiten.
Und ja, du hast nach weiteren C-artigen Lösungen gefragt, also habe ich
eine gegeben (ich widerspreche dir nur, dass es ein "falscher" Hinweis
ist). :-)
Yalu X. schrieb:> Sendet man den String mit einem gewöhnlichen Terminalprogramm, muss man> die Zeichen zügig eintippen, um zu vermeiden, dass der Timeout schon vor> dem Ende der Eingabe zuschlägt.
der gemeine Arduino User wird auch nicht unbedingt das Verlangen haben,
andere Terminal/Monitorprogramme zu benutzen. Bei externen Programmen
muss man nämlich immer erst den Port zumachen bevor ein neues Programm
geladen werden kann, es wird ja üblicherweise die selbe serielle
Schnittstelle benutzt.
Davon ab können aber viele alternative Programme auch eine Zeile am
Stück oder per Makro Sequenzen auf Knopfdruck senden, das gute alte Br@y
Terminal mal als Beispiel. Terminal Emulationen sind eher selten, seit
MS kein Hyperterminal mehr mit ausliefert kenn das keiner mehr :)
Johannes S. schrieb:> der gemeine Arduino User wird auch nicht unbedingt das Verlangen haben,> andere Terminal/Monitorprogramme zu benutzen.
oh ich bin ein ungemeiner User?
Ich nutze meine Arduino Projekte auch auch abgesetzt von der IDE und
mache Terminal Programme auf um das Modul zu steuern, Uhrzeit Datum der
RTC korrigieren, automatische Rolladen Zeiten anzupassen, oder Rolladen
manuell fernzusteuern. Die Rolläden werden per 433 MHz fernbedient, auch
mal Funksteckdosen, oder meine wordclock12h per wUSB.
Wenn ich die umprogrammieren will nutze ich wUSB oder sharkoon 100/400
USB Server im LAN über die Ardunio IDE, was aber sehr selten ist das die
SW im Wesentlichen steht.
Arduino Fanboy D. schrieb:>> Auch damit wechselst du zwischen C und C++.,>> was unnötige Konvertierung erfordert> Das passiert nur in deinem Kopf.
Das mag sein. Du siehst: Es macht den Quelltext für mich schwieriger
lesbar. Deswegen ist er nicht falsch oder schlecht. ich wollte nur
sagen, dass es nicht mein Stil ist und eine Alternative vorschlagen.
Yalu X. schrieb:> Zu dem Code wäre noch anzumerken, dass auch readString() ...> als einziges Kriterium für das String-Ende einen Timeout verwendet.
Wie bei den HC-06 Modulen. Wer hat sich da wohl von wem inspirieren
lassen?
Sage mal kann es sein, dass Serial.readString() unf readStringUntil()
beliebig viele Zeichen einliest?
Ich hatte das Problem mal mit einem ESP8266 auf einem IP Socket, da
schmierte mir der Chip immer ab, wenn die Strings länger als 5kB wurden.
Vermutlich wegen Stack-Überlauf.
Stefan ⛄ F. schrieb:> Über wie viele Artikel haben die denn die Doku dieser einen Klasse> verstreut?
ich hadere auch mit der Doku, aber egal es geht auch anders!
Du kannst den String-Datentyp verwenden, der ab Version 0019 Teil des Kerns ist oder du kannst einen String aus einem Array des Typs char erstellen und ihn mit einem Nullterminator abschließen. Diese Seite beschreibt die letztere Methode. Für weitere Informationen zum String-Objekt, das mehr Funktionalität auf Kosten von mehr Arbeitsspeicher bietet, siehe die string object-Seite.
Inklusive Link zur Doku der String-Klasse. Was will man mehr? Im zweiten
Link steht das gleiche auf englisch (wie zu erwarten, da es die
englische Version der gleichen Seite ist)
Chregu schrieb:> Ich verwende erfolgreich in der Loop folgenden Code:> (gekürzt aufs Nötigste)
Offenbar zu viel gekürzt. Wenn der String länger ist, als der Puffer,
stürzt das Ding ab.
Arduino Fanboy D. schrieb:> Schwer vorstellbar, dass du damit überfordert bist.
Oh bitte, ich habe mir diese Spielzeugsprache gut 2 Stunden angesehen -
und das hat mir gereicht.
Arduino Fanboy D. schrieb:> Schwer vorstellbar, dass du damit überfordert bist, den richtigen Ort zu> finden, und die Buffergröße nach Wunsch einzustellen.
#IchhabBessereszutun
Jede vernünftige Seriel-Lib hat eine Möglichkeit, die Buffergröße
einfach zu setzen, ohne im Code der Lib rumkrauchen zu müssen.
Gerade bei Arduino ist das essentiell, weil sonst einfach der Stack
überschrieben wird.
Chregu schrieb:> Ich verwende erfolgreich in der Loop folgenden Code:> (gekürzt aufs Nötigste)
Oh Glückwunsch.
Ich mein, warum macht man sowas? Fehlerhafte Masseanbindung, falsche
Baudrate, abweichender Baudratenquarz, falsch eingestelltes Terminal -
oder eine Faxsoftware die nach einem Modem sucht... es gibt so viele
Möglichkeiten einen RS232 mit falschen Daten zu fluten - und dabei
jedesmal den Stack ins Nirwana zu schicken.
Nur weil man sich eine Buffer Overflow oder String Overflow Prüfung
sparen will.
Stefan ⛄ F. schrieb:> Offenbar zu viel gekürzt. Wenn der String länger ist, als der Puffer,> stürzt das Ding ab.
eben
if(isprint(incomingByte)) {
if(chr_cnt<(MAXBUFFER-2))
serial_in_buff[chr_cnt++] = incomingByte;
else {
Serial.println(F("serBUF ov-> DEL"));
memset(&serial_in_buff[0], 0, sizeof(serial_in_buff));
memset(&serial_in_command[0], 0, sizeof(serial_in_command));
chr_cnt=0;
} // if !(chr_cnt<(MAXBUFFER-2))
} // if(isprint(incomingByte))
Karl K. schrieb:> Oh bitte, ich habe mir diese Spielzeugsprache gut 2 Stunden angesehen -> und das hat mir gereicht.
C++ ist also eine "Spielzeugsprache"?
Alles klar....
Keine Fragen mehr.
Karl K. schrieb:> Jede vernünftige Seriel-Lib hat eine Möglichkeit, die Buffergröße> einfach zu setzen, ohne im Code der Lib rumkrauchen zu müssen.>> Gerade bei Arduino ist das essentiell, weil sonst einfach der Stack> überschrieben wird.
Irrational!
Wie du auf solche Ideen kommst, ist mir ein Rätsel.
Die 2 Stunden haben offensichtlich nicht gerecht, für ordentliche
Argumente.
Stefan ⛄ F. schrieb:> S. R. schrieb:>> Ich werfe folgendes in den Raum:>> if (strncmp(befehl.c_str(), "ein", 3) == 0) {...}>> Auch damit wechselst du zwischen C und C++., was unnötige Konvertierung> erfordert und den eigenen Quelltext schlechter lesbar macht.>> Besser wäre in diesem Fall:>> if (befehl.indexOf("ein")==0) {...}
String::indexOf hat 2 Overloads. Eins für char, also Einzelzeichen und
eins für String, aber kein Overload für "const Char *", das funktioniert
nur, weil einen nicht-expliziten Konstructor für String gibt, der aus
"const char *" einen String macht. Und dabei wird erst mal ein neuer
String angelegt (auf dem Heap). "small string optimization", wie es in
"kompletten" C++-Libs zu finden ist, gibt es nicht, also werden für
"ein" 3 Bytes allokiert. Ist natürlich mit 64Bit Ptr/Länge/Kapazität,
also 24Byte Verwaltungdaten einfacher da notfalls den Inhalt direkt
reinzuschreiben, als beim AVR mit nur 6Byte.
Der String::operator==() hat ein Overload für "const char *" und kommt
ohne temporären String aus.
Und das eigentliche Problem waren ja das/die Whitespace(s) am Ende des
Befehls.
Allerdings kann man String leicht um fehlendes erweitern:
1
structmyString:PublicString{
2
intString::indexOf(constchar*cstr)const
3
{
4
// hier darf man mit str..irgendwas() das gewünschte implementieren
5
// also cstr in this.buffer suchen
6
}
7
};
Bei String ist das offensichtlich vorgesehen, da alle internen
Daten/Methoden protected sind, also für Ableitungen sichtbar.
Karl K. schrieb:> Aber bitte, wenn C++ so toll ist, warum wurde dann Rust entwickelt?
Oder python? Oder C#? oder Basic?
Mich erinnert Rust an Pascal.
Meist werden neue Programmiersprachen entwickelt, weil jemand "zu doof
oder zu faul" für die herkommlichen ist oder sie etwas "Modernes" nicht
einfach so unterstützen (GUI-Programmierung in C auf einem
Windows-Rechner war damals ziemlich aufwendig).
Oder sie einfach als alt und unmodern ("nicht mehr hip") angesehen
werden.
Karl K. schrieb:> Aber bitte, wenn C++ so toll ist, warum wurde dann Rust entwickelt?
Rust wurde für Projekte gemacht, die Hosenträger + Gürtel brauchen.
Stefan ⛄ F. schrieb:> Karl K. schrieb:>> Aber bitte, wenn C++ so toll ist, warum wurde dann Rust entwickelt?>> Rust wurde für Projekte gemacht, die Hosenträger + Gürtel brauchen.
Der Kollege Karl hat schon lange eingesehen, dass seine Argumente an den
Haaren herbei gelogen sind.
Anstatt sich auf einen Dialog einzulassen, greift er zum Mittel, welches
sich auf Neudeutsch "whataboutism" nennt.
Oder einfach nur "Nebelkerzen".
Karl K. schrieb:> Ich bin mir ziemlich sicher dass du weißt, ich meine damit das was unter> Arduino drauß gemacht wurde.
Ja!
Ich denke schon...
C++ ist C++, und die Arduino Entwickler haben das nicht verändert.
Es ist ok, wenn du C++ nicht magst.
Es ist auch ok, wenn dir Arduino nicht schmeckt.
Aber was mir nicht schmeckt, ist dein Arduinobashing mit solchen
Scheinargumenten/Nebelkerzen/Lügen.
Von mir aus können wir beide uns gerne sachlich über Arduino und die
Zusammenhänge unterhalten.
Oder es auch sein lassen......
Stefan ⛄ F. schrieb:> Rust wurde für Projekte gemacht, die Hosenträger + Gürtel brauchen.
Klar, wir lieben sie doch alle: Die Angriffe, weil die Länge der Url im
Eingabefeld nicht begrenzt ist - und ausführbarer Code in den Speicher
geschrieben wird. Oder nicht sichtbare Zeichen, die dann
Speicherbereiche überschreiben.
Sowas gab es vor 25 Jahren - und sowas gibt es heute immer noch.
Soviel zu
STK500-Besitzer schrieb:> Meist werden neue Programmiersprachen entwickelt, weil jemand "zu doof> oder zu faul" für die herkommlichen ist
Ja, weil viele Programmierer sich absurd überschätzen und glauben nur
die anderen machen Fehler.
Siehe oben: Auf Buffer Overflow prüfen brauch ich nicht, ich schick ja
immer nur 3 Zeichen.
Und dann rumheulen, wenn man tagelang einen Fehler nicht findet, der µC
schon immer abstürzt bevor man überhaupt zum Testen kommt - weil der
Stack überschrieben wird. Weil man ein if sparen wollte.
Karl K. schrieb:> Und dann rumheulen, wenn man tagelang einen Fehler nicht findet, der µC> schon immer abstürzt bevor man überhaupt zum Testen kommt - weil der> Stack überschrieben wird. Weil man ein if sparen wollte.
ist leider so musste ich auch erst lernen, deswegen kommt nach
Serial.begin erst mal Mist auslesen!
Serial.begin(19200);
// while(Serial.available())
// Serial.read();
Serial.flush();
offensichtlich steht schon vorher was im Empfangsbuffer, woher? keine
Ahnung denn ich sende vorher ja nichts, kann also Einstrahlung sein!
Das betrifft bei mir übrigens mehrere AVR, auch der NETIO von Pollin hat
mit Arduino nichts zu tun!
Das führt am NETIO mit Radig SW regelmäßig zu einem Pufferüberlauf!
Die habe ich aber nie angepasst und dürfte auch nie den Pufferüberlauf
prüfen oder gar auf isprint testen!
Arduino Fanboy D. schrieb:> Aber was mir nicht schmeckt, ist dein Arduinobashing mit solchen> Scheinargumenten/Nebelkerzen/Lügen.
Oh bitte, lern erstmal Datentypen.
Beitrag "AVR Inline Optimierung kaputt?"
Genau diese Scheisse. Immer wieder. Seit zig Jahren. Und wird verteidigt
bis aufs Messer.
Joachim B. schrieb:> offensichtlich steht schon vorher was im Empfangsbuffer, woher?
Ein AVR liefert gern erstmal ein $00 einfach durch den Pegelwechsel beim
Einstecken, weil am Uart ein Startbit erkannt wird. Je nachdem ob die
Uart Fehlerbits ausgewertet werden, landet das dann im Buffer.
Andere Gründe hab ich oben schon genannt, alles erlebt. Und nur deswegen
unkritisch - weil man sich halt als Erstes Gedanken macht wie man Daten
so behandelt, dass der Controller nicht dadurch lahmgelegt wird.
Ich mein, dass ist seit zig Jahren Praxis, aber dennoch schlagen immer
wieder Leute auf, die meinen es besser zu wissen. Und wiederholen die
Fehler von vor zig Jahren.
Karl K. schrieb:> Beitrag "AVR Inline Optimierung kaputt?">> Genau diese Scheisse. Immer wieder. Seit zig Jahren. Und wird verteidigt> bis aufs Messer.
Naja, Thema war dort schlussendlich Undefined Behaviour (UB). Davon kann
sich Rust auch nicht freisprechen:
https://doc.rust-lang.org/reference/behavior-considered-undefined.html
C ist darauf optimiert,
- schnell zu sein
- auf möglichst vielen Plattformen zu laufen
Beides kann man nur unter einen Hut bekommen, wenn man einiges
schlichtweg als UB deklariert.
Frank M. schrieb:> Naja, Thema war dort schlussendlich Undefined Behaviour (UB). Davon kann> sich Rust auch nicht freisprechen:
Ja, aber wenn Du den Artikel bei Heise gelesen hättest, würdest Du
verstehen: UB ist bei C(++) Standard, bei Rust muss man es wollen.
Du kannst mit Rust alle Fehler machen, die Du auch mit C(++) machen
kannst. Aber eben nicht aus Versehen, sondern weil Du es willst.
Frank M. schrieb:> C ist darauf optimiert,> - schnell zu sein> - auf möglichst vielen Plattformen zu laufen
Ich hab mal ne Weile Ada programmiert, das erzeugte asm-Listing für AVR
war nicht viel anders als von C für gleiche Funktionen. Wie schnell ein
Programm am Ende ist hängt nicht davon ab, wie sehr Dir der Kompiler auf
die Finger haut.
Karl K. schrieb:> Ich hab mal ne Weile Ada programmiert, das erzeugte asm-Listing für AVR> war nicht viel anders als von C für gleiche Funktionen. Wie schnell ein> Programm am Ende ist hängt nicht davon ab, wie sehr Dir der Kompiler auf> die Finger haut.
Einfaches Beispiel: C/C++ reduziert den Ausdruck
1
x*2/2
einfach zu x. Das kann Rust nicht so einfach machen, weil hier ein
etwaiger Überlauf zu berücksichtigen ist.
Aber okay, der Anspruch, auf möglichst vielen Plattformen zu laufen,
wirkt da vermutlich schwerer. Rust garantiert zum Beispiel bei
Integer-Overflows ein Wrapping mit 2er Komplement im Release-Mode (Panic
im Debug-Mode). Wenn das eine CPU nicht kann, muss der Rust-Compiler per
Code nachhelfen. Dem C-Compiler ist das vollkommen egal, für ihn ist der
Overflow von Signed Integers einfach UB, fertig.
Und so kann ich mir auch andere Beispiele vorstellen, wo die Portierung
von Rust auf eine andere CPU durchaus mehr Arbeit machen kann als die
Portierung eines C-Compilers.
Interessante Lektüre:
http://huonw.github.io/blog/2016/04/myths-and-legends-about-integer-overflow-in-rust/
Karl K. schrieb:> Du kannst mit Rust alle Fehler machen, die Du auch mit C(++) machen> kannst. Aber eben nicht aus Versehen, sondern weil Du es willst.
Die Rust Regeln können einen stark einschränken, wie man etwas lösen
kann. Dann kann es viele einfache Lösungen geben, aber nutzt man die,
statt das halbe Programm neu zu designen, ist es "es falsch machen
wollen". Ich bezweifle mal stark, dass das immer zu gutem Programmdesign
führt.
Ausserdem, werden Stack overflows in ach so safem Rust Code mittlerweile
endlich im vornherein abgefangen? Ich sag nur Box::new([-1; 3000000]).
So viel zum Thema Rust und Fehlersicherheit...
Karl K. schrieb:>> Rust wurde für Projekte gemacht, die Hosenträger + Gürtel brauchen.>> Klar, wir lieben sie doch alle: Die Angriffe, weil die Länge der Url im> Eingabefeld nicht begrenzt ist - und ausführbarer Code in den Speicher> geschrieben wird. Oder nicht sichtbare Zeichen, die dann> Speicherbereiche überschreiben.>> Sowas gab es vor 25 Jahren - und sowas gibt es heute immer noch.
Genau. Manche Projekte brauchen eher Sicherheit als Performance, und da
macht Rust Sinn.
Karl K. schrieb:> Aber bitte, wenn C++ so toll ist, warum wurde dann Rust entwickelt?
Weil "Fortschritt" erstmal einen "Schritt" braucht.
Ob der nach vorne, zur Seite oder sogar nach hinten geht, lässt sich
vorher oft nicht vorhersehen.
Es ist heutzutage erstaunlich einfach, mal eben schnell eine
Programmiersprache aus dem Boden zu stampfen... und es gibt viele davon.
S. R. schrieb:> Ob der nach vorne, zur Seite oder sogar nach hinten geht, lässt sich> vorher oft nicht vorhersehen.
Ist auch eine Frage des Anwendungsfalls.
Die Möglichkeit, sehr dünne Scheiben herzustellen, ist zum Beispiel für
Smartphones eine gute Sache, aber für Fensterscheiben nutzlos.
Stefan ⛄ F. schrieb:> Die Möglichkeit, sehr dünne Scheiben herzustellen, ist zum Beispiel für> Smartphones eine gute Sache, aber für Fensterscheiben nutzlos.
Dünne Scheiben sind auch beim Smartphone eine schlechte Sache, wenn sie
bei jeder Erschütterung einen Sprung bekommt. Bei meinen Fenstern wären
dünnere Scheiben praktisch, da das Gewicht der Dreifachverglasung ein
echtes Problem ist.
Stefan ⛄ F. schrieb:> Die Möglichkeit, sehr dünne Scheiben herzustellen, ist zum Beispiel für> Smartphones eine gute Sache, aber für Fensterscheiben nutzlos.
Mehrscheiben-Sicherheitsglas. Bruchsicheres Vitrinenglas. Ein Bekannter
hat jahrelang Fenster eingebaut - und wäre über dünnere und damit
leichtere Scheiben sehr erfreut gewesen.
Man denkt ja häufig nur nicht über seinen Tellerrand hinaus...
🐧 DPA 🐧 schrieb:> So viel zum Thema Rust und Fehlersicherheit...
Du hast offenbar das Problem nicht verstanden:
Es wird nicht behauptet, dass Rust eine fehlerfreie Programmiersprache
wäre.
Es geht darum, dass man bei Rust typische Fehler nur machen kann, wenn
man die Sicherheit ABschaltet.
Während man bei C(++) um diese Fehler sicher auszuschließen die
Sicherheit EINschalten muss.
Jochen S. schrieb:> Vielleicht ist der gelesene String länger? Um ein CR und/oder LF> vielleicht?
Soweit waren wir schon am 25.08.2020.
befehl.trim() hat's behoben, auch wenn die Arduino-Dokumentation auf
Deutsch behauptet, es entfernt nur Leerzeichen: es arbeitet wie in der
Englischen Dokumentation beschrieben und entfernt "Whitespace".