Boa Constructor schrieb:> In C/C++ kriege ich keine einfachen Stringverknüpfungen hin.>> Bin Laie. Dachte aber, es geht so wie in anderen Sprachen:
Mit std::string geht das. Die "" sind in C oder C++ keine Strings,
sondern char arrays und etwas eigen. Du musst eine Funktion wie strcat
benutzen und dich zudem um das Reservieren neuen Speichers kümmern.
> Serial.println("Boa" + "Constructor");
std::string hat den operator +:
z.B.
Serial.println(std::string("Boa") + "Constructor");
...falls die Funktion std::string als Argument akzeptiert.
Ansonsten:
(std::string("Boa") + "Constructor").c_str()
Mikro 7. schrieb:> (std::string("Boa") + "Constructor").c_str()
Fraglicher Pattern, das funktioniert genau wenn es direkt als Argument
einer Funktion benutzt wird (die es sich zudem nicht merken darf) und
ansonsten nicht.
Sven B. schrieb:> Mikro 7. schrieb:>> (std::string("Boa") + "Constructor").c_str()>> Fraglicher Pattern, das funktioniert genau wenn es direkt als Argument> einer Funktion benutzt wird (die es sich zudem nicht merken darf) und> ansonsten nicht.
was?
Boa Constructor schrieb:> Sven B. schrieb:>> Mikro 7. schrieb:>>> (std::string("Boa") + "Constructor").c_str()>>>> Fraglicher Pattern, das funktioniert genau wenn es direkt als Argument>> einer Funktion benutzt wird (die es sich zudem nicht merken darf) und>> ansonsten nicht.>> was?
Das baut einen temporären std::string, und gibt dir dann einen Pointer
auf dessen interne Daten. Sobald der temporäre std::string zerstört wird
(was bei diesem Konstrukt quasi immer sofort passiert, außer es ist
Argument einer Funktion -- dann bleibt es am Leben, bis die Funktion
ausgeführt wurde) ist der Pointer ungültig.
Folgendes ist also ok:
func((std::string("Foo") + "Bar").c_str());
aber das nicht:
char* a = (std::string("Foo") + "Bar").c_str();
func(a);
Dies habe ich bis jetzt getan. Nur mit mehr Strings. Gab irgendwann
Performanceprobleme, daher will ich davon weg.
Das einzige, was bis jetzt geht, ist das hier.
Boa Constructor schrieb:> g457 schrieb:>> Serial.println("Boa" "Constructor");>> geht.
Das funktioniert, solange du Literals benutzt. Mit Variablen gehts es
aber nicht.
>> #include <string>>> Ändert nichts. In allen Varianten nicht, auch nicht mit string.h
Brummbär schrieb:> Boa Constructor schrieb:>> Ändert nichts. In allen Varianten nicht, auch nicht mit string.h>> Was verwendest Du denn. C oder C++?
k. Ahn., die Arduino IDE. ich denke C++ ist drin
Mikro 7. schrieb:> Boa Constructor schrieb:>> g457 schrieb:>>> Serial.println("Boa" "Constructor");>>>> geht.>> Das funktioniert, solange du Literals benutzt. Mit Variablen gehts es> aber nicht.>>>> #include <string>>>>> Ändert nichts. In allen Varianten nicht, auch nicht mit string.h>>
Boa Constructor schrieb:> Dies habe ich bis jetzt getan. Nur mit mehr Strings. Gab irgendwann> Performanceprobleme, daher will ich davon weg.
Performanceprobleme?
Glaube ich nicht!
Hier noch eine Variante:
1
#include<Streaming.h> // suche nach "Arduino Streaming.h"
2
3
voidsetup()
4
{
5
Serial.begin(9600);
6
Serial<<"Boa"<<"Constructor"<<endl;
7
}
8
9
voidloop(){}
Boa Constructor schrieb:> Das funzt leider auch nicht. Oder bin ich zu blöd dazu, kann das sein?> #include <string>
Bei der AVR ToolChain ist die STL nicht dabei.
Arduino Fanboy D. schrieb:> Bei der AVR ToolChain ist die STL nicht dabei.
Habe ich auch gerade gesehen. Also kein vollst. C++ Support.
@Boa: Dann ignoriere mein Postings.
Mikro 7. schrieb:> Arduino Fanboy D. schrieb:>> Bei der AVR ToolChain ist die STL nicht dabei.>> Habe ich auch gerade gesehen. Also kein vollst. C++ Support.>> @Boa: Dann ignoriere mein Postings.
keine Ursache. Danke trotzdem.
Arduino hat eine eigene String Klasse, die ist hier dokumentiert:
https://www.arduino.cc/reference/en/language/variables/data-types/string/
Die einzig sinnvolle Antwort hat hier jedoch Dirk gegeben: Man soll die
Strings nicht zusammenfügen, wenn es vermeidbar ist.
Und zwar schlicht und ergreifend deswegen, weil man dann zumindest
zeitweise doppelt so viel RAM belegt. Die beiden Quell-Strings belegen
bereits Speicher und das Ergebnis der Zusammenfügung belegt nochmal
Speicher.
Dazu kommt, dass man durch String-Manipulation Ratz-Fatz einen
fragmentierten Heap produziert, der zu einem Heap/Stack Überlauf führt.
https://hackingmajenkoblog.wordpress.com/2016/02/04/the-evils-of-arduino-strings/
Stefanus F. schrieb:> Arduino hat eine eigene String Klasse, die ist hier dokumentiert:> https://www.arduino.cc/reference/en/language/variables/data-types/string/>> Die einzig sinnvolle Antwort hat hier jedoch Dirk gegeben: Man soll die> Strings nicht zusammenfügen, wenn es vermeidbar ist.>> Und zwar schlicht und ergreifend deswegen, weil man dann zumindest> zeitweise doppelt so viel RAM belegt. Die beiden Quell-Strings belegen> bereits Speicher und das Ergebnis der Zusammenfügung belegt nochmal> Speicher.>> Dazu kommt, dass man durch String-Manipulation Ratz-Fatz einen> fragmentierten Heap produziert, der zu einem Heap/Stack Überlauf führt.>> https://hackingmajenkoblog.wordpress.com/2016/02/04/the-evils-of-arduino-strings/
Ist schon klar. Ob der uC Garbage Collection kann (?) ist ja auch egal,
lags will ich nicht provozieren. Momentan habe ich aber zuweilen eine
Rekursion im ISR, wenn dort zu viele Serial.print ausgegeben werden. Was
soll ich machen ohne Debugger. Es ist wie bei armen Leuten
Boa Constructor schrieb:> Ob der uC Garbage Collection kann (?)
Dafür bräuchtest du ein Betriebssystem, welches das steuert, und eine
Memory Mapping Unit. AVR sind davon sehr weit entfernt.
Stefanus F. schrieb:> Arduino hat eine eigene String Klasse, die ist hier dokumentiert:> https://www.arduino.cc/reference/en/language/variables/data-types/string/
ja das geht, danke schonmal.
Kann ich auch Zahlen in den String integrieren? Keine Literale, sondern
Variablen. also wer VB kennt, ist beeindruckt von dem Aufwand in c. Soll
aber keine Wertung sein, aber Stringverarbeitung ist (m.E.,) ein Kreuz
Stefanus F. schrieb:> Boa Constructor schrieb:>> Ob der uC Garbage Collection kann (?)>> Dafür bräuchtest du ein Betriebssystem, welches das steuert, und eine> Memory Mapping Unit. AVR sind davon sehr weit entfernt.
Habe ich vermutet. Die Andeutung war auch eher theoretisch.
Die "Garbage Collection" von C++ nennt sich Smart Pointer. Natürlich ist
das keine Garbage Collection im eigentlichen Sinne sondern nur die
automatisierte Freigabe von Resourcen gebunden i.d.R. an die Destruktion
des Smart Pointers (ein Objekt das eine Referenz auf die Resource
besitzt).
Eine Garbage Collection im klassischen Sinn muss die Sprache selbst
unterstützen. Das ist bei C und C++ nicht der Fall (und auch nicht
wünschenswert). Eine Memory Management Unit + OS sind hilfreich aber
eigentlich keine Voraussetzung. Die Garbage Collection ist bei
(teil)interpretierten Sprachen eng mit der VM gekoppelt.
Stefanus F. schrieb:> Boa Constructor schrieb:>> Kann ich auch Zahlen in den String integrieren?>> Du hast die Seite nicht wirklich gelesen. Ich zitiere:>
Ehrlich gesagt noch gar nicht. English quält mich immer so, da muss ich
Zeit+Ruhe haben. Bin gerade i.d. Küche am kochen :)
Programmieren ohne Englisch ist wie Kochen ohne Feuer. Weit kommt man
ohne Englisch nicht, da musst du durch.
Die Zeiten, wo man sich dicke Bücher auf deutsch kaufen konnte, sind
vorbei.
Boa Constructor schrieb:> Momentan habe ich aber zuweilen eine> Rekursion im ISR, wenn dort zu viele Serial.print ausgegeben werden.
Niemals in einer ISR Strings ausgeben. Das macht man nicht.
Eine ISR hat immer, bis auf ganz wenige Ausnahmen, so kurz wie möglich
zu sein. Keine Ausgaben, keine (großen) Berechnungen, keine Delays.
Brummbär schrieb:> Boa Constructor schrieb:>> Momentan habe ich aber zuweilen eine>> Rekursion im ISR, wenn dort zu viele Serial.print ausgegeben werden.>> Niemals in einer ISR Strings ausgeben. Das macht man nicht.> Eine ISR hat immer, bis auf ganz wenige Ausnahmen, so kurz wie möglich> zu sein. Keine Ausgaben, keine (großen) Berechnungen, keine Delays.
Ja Brummbär, entspann dich wieder :)
Boa Constructor schrieb:> Was soll ich machen ohne Debugger. Es ist wie bei armen Leuten
Boa Constructor schrieb:> Dies habe ich bis jetzt getan. Nur mit mehr Strings. Gab irgendwann> Performanceprobleme, daher will ich davon weg.
Bei Strings sollte man sich erstmal ein einheitliches Format überlegen,
denn meistens sind Ausgaben recht ähnlich aufgebaut. Das erleichert es
auch, die Ausgaben konsistent und ohne Schreibfehler zu halten.
Obenrdrein spart es auch massig Speicher.
Ich hab da schon die dollsten Sache erlebt, wenn alle Ausgaben einzeln
definiert werden, z.B.:
"Error xxx\n"
"error xxx\n"
"Eror xxx\n"
"Error: xxx\n"
"Error xxx!\n"
"Erorr: xxx !\n"
Beim AVR muß man etwas tricksen, damit Stringkonstanten nicht im RAM
dupliziert werden.
Konkretisiert schlägt der Wachhund an, wenn ich (testweise) 2 Meßreihen
a' 5 Werte ausgebe. Das sind 2x 5 Werte mit 2x4 Tabs ("\t") dazwischen,
also insg. 18 Serial.print. Das ist zuviel Last, weiß ich. Der ISR
taktet mit 160 Hz.
Boa Constructor schrieb:> Konkretisiert schlägt der Wachhund an
Der Watchdog hat in der Entwicklungsphase inaktiv zu sein. Man will ja
alle Fehler sehen und sie nicht verstecken.
Peter D. schrieb:> Boa Constructor schrieb:>> Dies habe ich bis jetzt getan. Nur mit mehr Strings. Gab irgendwann>> Performanceprobleme, daher will ich davon weg.>> Bei Strings sollte man sich erstmal ein einheitliches Format überlegen,> denn meistens sind Ausgaben recht ähnlich aufgebaut. Das erleichert es> auch, die Ausgaben konsistent und ohne Schreibfehler zu halten.> Obenrdrein spart es auch massig Speicher.> Ich hab da schon die dollsten Sache erlebt, wenn alle Ausgaben einzeln> definiert werden, z.B.:> "Error xxx\n"> "error xxx\n"> "Eror xxx\n"> "Error: xxx\n"> "Error xxx!\n"> "Erorr: xxx !\n">> Beim AVR muß man etwas tricksen, damit Stringkonstanten nicht im RAM> dupliziert werden.>>
>> header, footer können auch als Array mit fester Stringlänge im PROGMEM> definiert werden.
ich mache das bis jetzt so:
1
#define SP(zahl) Serial.print(zahl) // Zahl seriell ausgeben
2
#define SPLN(zahl) Serial.println(zahl) // Zahl seriell ausgeben mit Zeilenumbruch
3
#define SPT(text) Serial.print(F(text)) // Text seriell ausgeben
4
#define SPTLN(text) Serial.println(F(text)) // Text seriell ausgeben mit Zeilenumbruch
5
#define SPTAB Serial.print("\t") // Tab ausgeben
aber das ist natürlich nicht performant, nur ein Workarround. Ich muss
das jetzt verfeinern.
Ansonsten ist das auch nicht kritisch, wenn der Ticker den lfd. Prozess
einholt, nur unschön.
Peter D. schrieb:> Boa Constructor schrieb:>> Konkretisiert schlägt der Wachhund an>> Der Watchdog hat in der Entwicklungsphase inaktiv zu sein. Man will ja> alle Fehler sehen und sie nicht verstecken.
Ist doch kein Watchdog. Nur mein persönlicher "Wachhund" :-) Am
ISR-Eingang wird, solange dort drin Code ausgeführt wird, abgefragt, ob
der Event erneut aufgerufen wird. sei() ist natürlich immer aktiv, sonst
geht das nicht. Ein rekursiver (oder wie sagt man hier..?) Aufruf wird
mit "return" abgeblockt, so dass der Ticker nicht blockiert wird,
solange im ISR code läuft.
Stefanus F. schrieb:> Programmieren ohne Englisch ist wie Kochen ohne Feuer. Weit kommt man> ohne Englisch nicht, da musst du durch.
Ich kanns ja, es quält mich nur.
Und glaube mir, kochen ohne Feuer geht. Ich bin doch gerade in der
Küche, am Kochen :)
Boa Constructor schrieb:> ich mache das bis jetzt so:
Define ist kein Funktionsaufruf, d.h. der Code wird bei jeder Verwendung
dupliziert. Mach ne Funktion draus, nur dann spart man auch.
Peter D. schrieb:> Boa Constructor schrieb:>> ich mache das bis jetzt so:>> Define ist kein Funktionsaufruf, d.h. der Code wird bei jeder Verwendung> dupliziert. Mach ne Funktion draus, nur dann spart man auch.
Lohn nicht. Prints gibts nur i.d. entwicklung, als Debugger für arme.
So, habe ein wenig i.d. reference gestöbert u. 1 Lösung gefunden. Es
scheint auch zu funktionieren, auch wenn es einfach aussieht
https://www.arduino.cc/reference/en/language/variables/data-types/stringobject/
Ob das jetzt performanter ist, weiß ich nicht. Heute werde ich das nicht
mehr testen. Habs nur geschrieben, falls jemand dasselbe Problem hat,
kann er/sie hier fündig werden.
Danke an alle.
Noch eine Info für die Nachwelt:
Habe mich noch mal eingelesen. String (mit großem 'S') ist als
Speicher-Fragmentierer verpönt. Das sollte man dann wissen. Mir macht's
nichts, weil es nur zur Entwicklungszeit verwendet wird. Au jeden Fall
will ich den tipp nicht gegeben haben, ohne darauf zu verweisen.
Boa Constructor schrieb:> Noch eine Info für die Nachwelt:>> Habe mich noch mal eingelesen. String (mit großem 'S') ist als> Speicher-Fragmentierer verpönt.
Das gilt ganz besonders, wenn man es so benutzt wie in deinem Beispiel
> Das sollte man dann wissen. Mir macht's nichts, weil es nur zur> Entwicklungszeit verwendet wird.
Das hat nicht viel damit zu tun. Entweder der Speicher (und die
Rechenzeit) reicht für dein Programm mit diesen ganzen Strings, dann
stört es auch in der Release-Version nicht, oder es reicht nicht, dann
funktioniert aber deine Entwickler-Version nicht.
Arduino Fanboy D. schrieb:> Ist klar!
Ja du lässt die Leut' ins offene Messer laufen. Ein toller Ratgeber,
muss ich schon sagen, Respekt.
Rolf M. schrieb:> Boa Constructor schrieb:>> Noch eine Info für die Nachwelt:>>>> Habe mich noch mal eingelesen. String (mit großem 'S') ist als>> Speicher-Fragmentierer verpönt.>> Das gilt ganz besonders, wenn man es so benutzt wie in deinem Beispiel
Was konkret ? Nur zum lernen, Speicher ist noch genug frei
Boa Constructor schrieb:> Ja du lässt die Leut' ins offene Messer laufen. Ein toller Ratgeber,> muss ich schon sagen, Respekt.
Du irrst!
(etwas plemplem heute?)
Boa Constructor schrieb:> 18 Serial.print. Das ist zuviel Last, weiß ich. Der ISR> taktet mit 160 Hz
Das ist kein Problem der 18 Funktionsaufrufe (von Serial.print)
Es sind zuviel Daten für deine 160 Hz.
bei 9600 Baud / 10 (Bits pro Zeichen) / 160 Hz komme ich auf 6 Zeichen
die vernünftig rüber kommen.
Und da wird nichts anderes mehr ausgeführt.
Boa Constructor schrieb:> Rolf M. schrieb:>> Boa Constructor schrieb:>>> Noch eine Info für die Nachwelt:>>>>>> Habe mich noch mal eingelesen. String (mit großem 'S') ist als>>> Speicher-Fragmentierer verpönt.>>>> Das gilt ganz besonders, wenn man es so benutzt wie in deinem Beispiel>> Was konkret ? Nur zum lernen, Speicher ist noch genug frei
Jedesmal, wenn du den Operator + verwendest, wird für das Ergebnis ein
neuer Speicherblock allokiert, der natürlich auch jedesmal etwas größer
ist, als der davor. Da werden dann die beiden Strings reinkopiert. Erst
ganz am Schluss wird alles wieder freigegeben.
Das da kostet also erstens jede Menge Rechenzeit, zweitens jede Menge
Speicher:
Boa Constructor schrieb:> Serial.println(String(i1)> + String("\t")> + String(i2)> + String("\t")> + String(i3)> + String("\t")> + String(i4)> + String("\t")> + String(i5));
Auf die Schnelle hab ich dazu auch die folgende ausführlichere Erklärung
gefunden:
https://hackingmajenkoblog.wordpress.com/2016/02/04/the-evils-of-arduino-strings/
Dirk B. schrieb:> Boa Constructor schrieb:>> 18 Serial.print. Das ist zuviel Last, weiß ich. Der ISR>> taktet mit 160 Hz>> Das ist kein Problem der 18 Funktionsaufrufe (von Serial.print)> Es sind zuviel Daten für deine 160 Hz.>> bei 9600 Baud / 10 (Bits pro Zeichen) / 160 Hz komme ich auf 6 Zeichen> die vernünftig rüber kommen.> Und da wird nichts anderes mehr ausgeführt.
Ja kann sein. Vermutlich hast du recht. Die Baudrate lässt sich
vielleicht hochsetzen.
Rolf M. schrieb:> Jedesmal, wenn du den Operator + verwendest, wird für das Ergebnis ein> neuer Speicherblock allokiert, der natürlich auch jedesmal etwas größer> ist, als der davor. Da werden dann die beiden Strings reinkopiert. Erst> ganz am Schluss wird alles wieder freigegeben.
OK, danke. Ja das leuchtet mir ein,
Boa Constructor schrieb:> .....> also dann Strings via Array vor-verketten und den (char)Pointer an> Serial.print übergeben? Nur mal so dahingedacht, bin kein c Profi
Wie gesagt ist der beste Weg, die Strings gar nicht zu verketten. Besser
jeden Teilstring einzeln ausgeben. Durch die serielle Schnittstelle
kommt das hinten als ein Datenstrom heraus, egal wie viele
"Serial.print" Aufrufe dazu nötig waren.
Dirk B. schrieb:> Wie schnell ist dein Controller? ca. 10 MHz?
16MHz
Stefanus F. schrieb:> Ich war derjenige, der den Artikel vorgeschlagen hat.
wos? brauche ich Brille?
nö, es steht 2x oben.
Dann danke an euch beide :))
Den Speicherverbrauch kann man während er Laufzeit sichtbar machen:
https://playground.arduino.cc/Code/AvailableMemory
Das würde ich mal tun, um die verschiedenen Theorien hier bezüglich der
Stringfunktionen zu überprüfen.
Diese Funktion ermittelt (auf den ersten Blick) die Summer aller freier
Speicherblöcke. Fragmentierung bemerkt man damit nicht.
Die folgende Funktion testet mit einer in 10er Schritten aus, wie viel
Speicher man an einem Stück belegen kann.
Man kann auch einfach plain C verwenden und mit strcat Strings
aneinander kopieren. Dann wird kein unnützer Speicher alloziert. Man ist
dann aber selber dafür verantwortlich, daß der Zielstring genügend groß
ist. Malloc wird nicht benötigt.
Mit strncat kann man absichern, daß der Zielstring nicht überläuft. Was
man zuviel reinschreiben will, wird abgeschnitten.
Peter D. schrieb:> und mit strcat Strings> aneinander kopieren.
Habe ich dem Roth gezeigt!
Aber dazu sagte er:
Boa Constructor schrieb:> du lässt die Leut' ins offene Messer laufen.
Stefanus F. schrieb:> Die folgende Funktion testet mit einer in 10er Schritten aus, wie viel> Speicher man an einem Stück belegen kann.> unsigned short function_freememory(char* buffer) {
Die Funktion ist krank oder sehr unsauber.
Gibt offensichtlich einen Zeiger zurück, ist aber als unsigned short
deklariert.
Das passt nicht.
Es wäre voll ausreichend, wenn sie nur ein size_t zurückgeben würde.
Die Stringgenerierung kann man doch anderen Zuständigkeiten überlassen.
Die korrekte Funktion der Funktion habe ich (noch) nicht getestet.
Arduino Fanboy D. schrieb:> Die Funktion ist krank oder sehr unsauber.> Gibt offensichtlich einen Zeiger zurück, ist aber als unsigned short> deklariert.
Sie gibt die Anzahl der Zeichen zurück, die in den Buffer geschrieben
wurden.
Ich bin ein bisschen erstaunt, dass du nicht mit der Funktion
sprintf_P() vertraut bist.
> Es wäre voll ausreichend, wenn sie nur ein size_t zurückgeben würde.> Die Stringgenerierung kann man doch anderen Zuständigkeiten überlassen.
Ja kann man. Ich habe das aus einem Programm heraus kopiert, wo es so
gebraucht wurde. Ich erlaube Dir hiermit ausdrücklich, den kopierten
Code nach deinen Bedürfnissen anzupassen. Zufrieden?
Cornelius schrieb:> Ich vermute, Arduino-String ist ein Versuch, sich der Java-API zu> nähern:
Das vermute ich auch.
Denn die ursprüngliche Basis/Vorbild soll wohl Processing sein.
Cornelius schrieb:> Das ist schon wahr, aber die Arduino-String-Funktionen sind so> unglaublich bequem:
Noch bequemer ist wohl das Streaming.
Zumindest bei den einfachen Ausgaben die in diesem Thread zu sehen sind.
Siehe: Beitrag "Re: Stringverknüpfung C/C++"
Stefanus F. schrieb:> Sie gibt die Anzahl der Zeichen zurück, die in den Buffer geschrieben> wurden.>> Ich bin ein bisschen erstaunt, dass du nicht mit der Funktion> sprintf_P() vertraut bist.
Sorry.
Den Punkt nehme ich zurück....
Es ist kein Zeiger, sondern die Anzahl Zeichen.
Allerdings wäre hier int der richtige Datentype.
> On failure, a negative number is returned.
Da ist unsigned sicherlich gänzlich falsch.