Don't understand the readStringUntil() behavior

I have the following code:

if (Serial.available() > 0) {
Serial.readStringUntil(SERIAL_START_CHAR);
Serial.read(); // read the Start-Char 'away'
readString = Serial.readStringUntil(SERIAL_STOP_CHAR);
...
}

If the first char in the InputBuffer is the SERIAL_START_CHAR at the time I call readStringUntil() is it read out of the buffer? I thought the until char is never read so I have to call a read() afterwards to throw the SERIAL_START_CHAR away. My first Data Char is cutted if I call the read()! I always send the SERIAL_START_CHAR. The SERIAL_STOP_CHAR is not at the end of the readString. Why the documentation of Arduino's functions are so bad?

Wir können alle Deutsch hier :slight_smile:
Was ist mit deinem anderen Thread?

String Stream::readStringUntil(char terminator)
{
  String ret;
  int c = timedRead();
  while (c >= 0 && c != terminator)
  {
    ret += (char)c;
    c = timedRead();
  }
  return ret;
}

terminator wird, soweit gefunden, aus dem input Stream entfernt.

Mit Englisch erreicht man mehr Leute.
Der Code funktioniert nur wenn ich ein peek() davor setze und nur entferne wenn der Char da ist. Das verstehe ich nicht, das macht keinen Sinn. Laut der Implementierung wird das erste Zeichen immer gelesen oder verstehe ich das falsch? Das ist natürlich großer Käse und müsse in der Doku erwähnt werden.

Die Dokumentation ist länger als der mitgelieferte Quelltext und behauptet nicht, dass das Terminalzeichen im Buffer verbleibt.

Aber du kannst ja einen Verbesserungsvorschlag für die Dokumentatiuon machen.

Am besten ganz auf den String Quark verzichten.

LeRoi:
Mit Englisch erreicht man mehr Leute.

Ja aber nur im internationalen Teil des Forums

Ach, ich kenn mich hier noch nicht aus, sorry! Aber ich dachte Programmierer können alle englisch lesen und einigermaßen schreiben. Auf deutsch kann ich mich natürlich konkreter ausdrücken, aber ich bin es aus anderen Foren gewohnt. Ich nehme jetzt folgenden Code. Der funktioniert, ist aber etwas schade, dass es bei der Doku keinen kurzen Hinweis gibt. Also muss man sich immer die Implementierung angucken.

if (Serial.peek() != SERIAL_START_CHAR) {
Serial.readStringUntil(SERIAL_START_CHAR);
}
Serial.read(); // read the Start-Char 'away'

Ach Quatsch, hatte einen Aussetzer. Der gesuchte Char wird wie du sagtest immer rausgelesen. Dann kann ich mir das natürlich sparen.

LeRoi:
Also muss man sich immer die Implementierung angucken.

Im Zweifel ist das immer eine gute Idee. Zum Glück kann man das recht einfach.

Aber nochmals, für stabilen Kode (der über Blink hinausgeht) ist es unklug Strings zu verwenden.

Wenn der Speicher knapp wird geben einem Strings den Todesstoß.
Sporadische, nicht erklärbare Fehler, mit debug code geht es, ohne stürzt es ab,... etc.

Ich benutze Strings und es funktioniert tadelos. In manchen Bereichen nehme ich auch einen char array, den ich dann wieder freigebe. Aber bis jetzt war es mit Strings simpel und gut. Außerdem werden diese (insbesondere der readString) immer in Beispielen verwendet.

Na dann. :wink:

Niemand zwingt dich mir zu glauben.

Also ich verwende hauptsächlich globale Variablen, auch wenn ich diesen Stil in anderen Bereichen natürlich vermeide. Ich versuche möglichst alle Arrays fest zu definieren und wiederzuverwenden. Am Anfang hatte ich in der loop immer wieder Variablen erzeugt, was zu Problemen führte. Nun könnte man auch static verwenden, ziehe dann aber lieber global vor, die ich mehrfach verwende. Der Programmzeiger kann sowieso nur an einer Stelle sein, also alles gut zu verfolgen und sicher. Du meinst ich sollte einen char buffer verwenden? Gut, könnte ich. Den müsste ich aber mit fester Größe wählen, der mitunter mehr Platz vom wertvollen SRAM braucht als nötig für die meiste Zeit. Und ständig Anlegen und Freigeben kommt doch aufs gleich raus wie einen String immer wieder zu verwenden, meinst du nicht? Sonst erkläre mir bitte die Hintergründe, ich sehe keinen Unterschied.

Mit den normalen 2 kB Speicher ist jede Art von dynamischer Speicherverwaltung wenig sinnvoll.

Fest angelegte Puffer klammere ich da mal aus, wenn sie einmalig mit malloc() angelegt werden.

Wenn du bei Strings keine Concatenationen mehr vornehmen kannst, weil keine Block in der richtigen Größe mehr vorhanden ist, siehst du das nur an verstümmelten und oder völlig fehlenden Ausgaben, oder einem ausgesprochen merkwürdigen Programmverhalten.

Ich habe sehr schlechte Erfahrungen mit den Strings gemacht.

Wenn du deine selbst sammeln möchtest, auf gehts!

Why the documentation of Arduino's functions are so bad?

Warum sind Warum-Fragen immer so schwer zu beantworten :wink:
Meine Tochter ist jetzt Mutter und wird bald selber gelöchert. Ätschi


Du meinst ich sollte einen char buffer verwenden? Gut, könnte ich. Den müsste ich aber mit fester Größe wählen, der mitunter mehr Platz vom wertvollen SRAM braucht als nötig für die meiste Zeit.

Was für einen Sketch hast du im Kopf, der den gleichen RAM mal für einen zu speichernden Text, mal für was ganz anderes braucht? Aber beides sinnvollerweise in globalen oder statischen Variablen?

Was machst du, wenn du keinen RAM für deinen dynamischen String hast?

michael_x:
Warum sind Warum-Fragen immer so schwer zu beantworten :wink:
Meine Tochter ist jetzt Mutter und wird bald selber gelöchert. Ätschi


Was für einen Sketch hast du im Kopf, der den gleichen RAM mal für einen zu speichernden Text, mal für was ganz anderes braucht? Aber beides sinnvollerweise in globalen oder statischen Variablen?

Was machst du, wenn du keinen RAM für deinen dynamischen String hast?

Ich habe keine zusätzlichen dynamischen Strings. Alle sind 'const String' (in meinem Code taucht niemals ein magic String auf + "abc") bis auf den read und write String. Sollte der Speicher nach Nutzung nicht wieder freisein? Natürlich ist er zwischendurch zerstückelt, aber bis jetzt bin ich an keine Grenze gestoßen. Läuft! Später mache ich sicher alles mal mit char Array und den ganzen C String befehlen statt den von Arduino. Bis jetzt sehe ich kein merkwürdiges Verhalten.

Sollte der Speicher nach Nutzung nicht wieder freisein?

Globale und Statische Variable : nein, da gibt es kein "Nach Nutzung".
Lokale Variable auf dem Stack : ja, die sind nach Ende der Funktion weg.
Heap (z.B. String - Objekte) sollten nur verwendet werden, wenn Speicher keine Rolle spielt, und 2kB (beim Uno) reichlich sind. Weil man eh nichts machen kann, wenn es klemmen sollte.

Fans von const String sei der F("Text im Flash")-Makro ans Herz gelegt. Erstens ist der Flash meist nicht so knapp wie der RAM. Zweitens merkt man Engpässe schon beim Compilieren und kann keine Überraschungen zur Laufzeit erleben.

Da ich noch genügend RAM frei habe sehe ich keinen Sinn Serial print vom Flash aus zu machen (was auch langsamer sein sollte). Ich nutze den Serial auch nicht mehr für den Monitor sondern nur noch für interne Übertragung, also würde das sowieso nur stören.

michael_x:
Globale und Statische Variable : nein, da gibt es kein "Nach Nutzung".
Lokale Variable auf dem Stack : ja, die sind nach Ende der Funktion weg.
Heap (z.B. String - Objekte) sollten nur verwendet werden, wenn Speicher keine Rolle spielt, und 2kB (beim Uno) reichlich sind. Weil man eh nichts machen kann, wenn es klemmen sollte.

Fans von const String sei der F("Text im Flash")-Makro ans Herz gelegt. Erstens ist der Flash meist nicht so knapp wie der RAM. Zweitens merkt man Engpässe schon beim Compilieren und kann keine Überraschungen zur Laufzeit erleben.

Und was sollte ich statt 'final static' String Objekte nehmen? Char Arrays benötigen doch auch den gleichen Speicher und ich werde bestimmt nicht alles in den Flash packen. Der RAM ist doch dafür da, einen schnellen Zugriff zu haben. Manchmal kann man es auch übertreiben mit den Belehrungen. Wenn es sehr knapp sein sollte, denke ich über Optimierungen nach. Bis jetzt ist es ausreichend.

Manchmal kann man es auch übertreiben mit den Belehrungen

Stimmt, aber Unsinn wie

ich werde bestimmt nicht alles in den Flash packen

sollte man sich besser auch verkneifen :wink:
Alles was mit Initialwert im RAM ist, hat auch eine Kopie im Flash.

(Andere Belehrungen spare ich mir jetzt, danke für den Hinweis)