Forum: Mikrocontroller und Digitale Elektronik Stringverknüpfung C/C++


von Boa Constructor (Gast)


Lesenswert?

In C/C++ kriege ich keine einfachen Stringverknüpfungen hin.

Bin Laie. Dachte aber, es geht so wie in anderen Sprachen:
1
void setup() {
2
  Serial.begin(9600);
3
  Serial.println("Boa" + "Constructor");
4
}
5
6
void loop() {
7
}

Auch mit "&" geht es nicht. Für einen Tipp danke ich.

von Sven B. (scummos)


Lesenswert?

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.

von Mikro 7. (mikro77)


Lesenswert?

>   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()

von Dirk B. (dirkb2)


Lesenswert?

Boa Constructor schrieb:
> Dachte aber, es geht so wie in anderen Sprachen:

Das solltest du bei C nicht machen.

: Bearbeitet durch User
von Sven B. (scummos)


Lesenswert?

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.

: Bearbeitet durch User
von Boa Constructor (Gast)


Lesenswert?

Mikro 7. schrieb:
> Serial.println(std::string("Boa") + "Constructor");
1
'string' is not a member of 'std'

von Boa Constructor (Gast)


Lesenswert?

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?

von Mikro 7. (mikro77)


Lesenswert?

Boa Constructor schrieb:
> Mikro 7. schrieb:
>> Serial.println(std::string("Boa") + "Constructor");
>
>
1
'string' is not a member of 'std'

#include <string>

von g457 (Gast)


Lesenswert?

> Serial.println("Boa" + "Constructor");
>
> Auch mit "&" geht es nicht. Für einen Tipp danke ich.

Serial.println("Boa" "Constructor");

HTH

von Dirk B. (dirkb2)


Lesenswert?

1
Serial.println("Boa");
2
Serial.println("Constructor");

von Sven B. (scummos)


Lesenswert?

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);

von Einer K. (Gast)


Lesenswert?

1
Serial.println("Boa"  "Constructor");

-------------
1
Serial.println(String("Boa")+String("Constructor"));

-----------
1
Serial.println(String("Boa")+"Constructor");

---------
1
char a[] = "Boa";
2
char b[] = "Constructor";
3
4
void setup() 
5
{
6
  char temp[strlen(a)+strlen(b)+1] = "";
7
  strcpy(temp,a);
8
  strcat(temp,b);
9
10
  Serial.begin(9600);
11
  Serial.println(temp);
12
}
13
14
void loop() {
15
}

von Boa Constructor (Gast)


Lesenswert?

g457 schrieb:
> Serial.println("Boa" "Constructor");

geht.




Mikro 7. schrieb:
> Boa Constructor schrieb:
>> Mikro 7. schrieb:
>>> Serial.println(std::string("Boa") + "Constructor");
>>
>>
1
'string' is not a member of 'std'
>
> #include <string>

Ändert nichts. In allen Varianten nicht, auch nicht mit string.h

von Brummbär (Gast)


Lesenswert?

Boa Constructor schrieb:
> Ändert nichts. In allen Varianten nicht, auch nicht mit string.h

Was verwendest Du denn. C oder C++?

von Boa Constructor (Gast)


Lesenswert?

Dirk B. schrieb:
>
1
Serial.println("Boa");
2
> Serial.println("Constructor");


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.
1
Serial.println("Boa" "Constructor");

Bei der anderen Variante kriege ich leider immer
1
'string' is not a member of 'std'

Danke bisher

von Mikro 7. (mikro77)


Lesenswert?

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
1
#include <string>
2
#include <stdio.h> // printf
3
4
int main()
5
{
6
  printf("%s\n",(std::string("Boa") + "Constructor").c_str()) ;
7
  return 0 ;
8
}

von Boa Constructor (Gast)


Angehängte Dateien:

Lesenswert?

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

von Boa Constructor (Gast)


Lesenswert?

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
>
>
1
> #include <string>
2
> #include <stdio.h> // printf
3
> 
4
> int main()
5
> {
6
>   printf("%s\n",(std::string("Boa") + "Constructor").c_str()) ;
7
>   return 0 ;
8
> }
9
>


Das funzt leider auch nicht. Oder bin ich zu blöd dazu, kann das sein?
1
#include <string>
2
3
                  ^
4
5
compilation terminated.
6
7
exit status 1
8
Fehler beim Kompilieren für das Board Arduino/Genuino Mega or Mega 2560.

von Einer K. (Gast)


Lesenswert?

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
void setup() 
4
{
5
  Serial.begin(9600);
6
  Serial << "Boa" << "Constructor" << endl;
7
}
8
9
void loop() {}

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.

von Boa Constructor (Gast)


Lesenswert?

mhh.

Niemand hat eine Idee? Dann brauche ich meine 2. Frage gar nicht zu 
stellen, wie ich Zahlenwerte in den Ausgabestring hinein bekomme.

von Mikro 7. (mikro77)


Lesenswert?

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.

von Boa Constructor (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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/

von Stefan F. (Gast)


Lesenswert?

> wie ich Zahlenwerte in den Ausgabestring hinein bekomme.

Wenn keine besondere Formatierung notwendig ist, dann fülle einen Puffer 
(char[]) mit atoi() oder atol(). Siehe 
https://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html

Wenn du Formatieroptionen brauchst, dann nimm printf(). Siehe 
https://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html

Die Serial Klasse von Arduino hat auch Funktionen für formatierte 
Ausgabe: 
https://www.arduino.cc/reference/en/language/functions/communication/serial/print/

von Boa Constructor (Gast)


Lesenswert?

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

von Stefan F. (Gast)


Lesenswert?

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.

von Boa Constructor (Gast)


Lesenswert?

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

von Boa Constructor (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

Boa Constructor schrieb:
> Kann ich auch Zahlen in den String integrieren?

Du hast die Seite nicht wirklich gelesen. Ich zitiere:

" For more details on the String object, which gives you more 
functionality at the cost of more memory, see the String object page."

Da hättest du nur drauf klicken brauchen.

https://www.arduino.cc/reference/en/language/variables/data-types/stringobject/

von x^2 (Gast)


Lesenswert?

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.

von Boa Constructor (Gast)


Lesenswert?

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 :)

von Stefan F. (Gast)


Lesenswert?

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.

von Brummbär (Gast)


Lesenswert?

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.

von Boa Constructor (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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.
1
#include <avr/pgmspace.h>
2
#include <stdint.h>
3
4
const char header_1[] PROGMEM = "header1";
5
const char footer_1[] PROGMEM = "footer1";
6
7
void display_item( char* buffer, char* header, uint16_t val, char* footer)
8
{
9
  sprintf_P(buffer, PSTR("%S %d %S\n"), header, val, footer);
10
}
11
12
void test(char* buffer)
13
{
14
  display_item(buffer, header_1, 1234, footer_1);
15
}

header, footer können auch als Array mit fester Stringlänge im PROGMEM 
definiert werden.

von Dr. Sommer (Gast)


Lesenswert?

Peter D. schrieb:
> Ich hab da schon die dollsten Sache erlebt, wenn alle Ausgaben einzeln
> definiert werden, z.B.:

Aber kein "Errör"?

von Boa Constructor (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von Boa Constructor (Gast)


Lesenswert?

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.
>
>
1
> #include <avr/pgmspace.h>
2
> #include <stdint.h>
3
> 
4
> const char header_1[] PROGMEM = "header1";
5
> const char footer_1[] PROGMEM = "footer1";
6
> 
7
> void display_item( char* buffer, char* header, uint16_t val, char* 
8
> footer)
9
> {
10
>   sprintf_P(buffer, PSTR("%S %d %S\n"), header, val, footer);
11
> }
12
> 
13
> void test(char* buffer)
14
> {
15
>   display_item(buffer, header_1, 1234, footer_1);
16
> }
17
>
>
> 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.

von Boa Constructor (Gast)


Lesenswert?

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.

von Boa Constructor (Gast)


Lesenswert?

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 :)

von Peter D. (peda)


Lesenswert?

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.

von Boa Constructor (Gast)


Lesenswert?

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/
1
void setup() 
2
{
3
byte i1 = 1;
4
byte i2 = 2;
5
byte i3 = 3;
6
byte i4 = 4;
7
byte i5 = 5;
8
  
9
  Serial.begin(9600);
10
  Serial.println(String(i1) 
11
             + String("\t")
12
             + String(i2) 
13
             + String("\t")
14
             + String(i3) 
15
             + String("\t")
16
             + String(i4) 
17
             + String("\t")
18
             + String(i5));
19
}
20
21
void loop() {}

von Boa Constructor (Gast)


Lesenswert?

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.

von Boa Constructor (Gast)


Lesenswert?

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.

von Einer K. (Gast)


Lesenswert?

Diese String Objekt Verwirrung will keiner.

Nutze das Streaming!

von Boa Constructor (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Diese String Objekt Verwirrung will keiner.

häh, Altersheimer? diese Verwirrung hast du doch selber eingestreut ^^ 
..

Arduino Fanboy D. schrieb:
>
1
> Serial.println(String("Boa")+String("Constructor"));
2
>
>
> -----------

>
1
> Serial.println(String("Boa")+"Constructor");
2
>
>
> ---------

usw

von Einer K. (Gast)


Lesenswert?

Boa Constructor schrieb:
> usw

Ist klar!

von Rolf M. (rmagnus)


Lesenswert?

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.

von Dirk B. (dirkb2)


Lesenswert?

wie schnell ist die serielle Schnittstelle eingestellt?

von Boa Constructor (Gast)


Lesenswert?

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

von Einer K. (Gast)


Lesenswert?

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?)

von Dirk B. (dirkb2)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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/

von Boa Constructor (Gast)


Lesenswert?

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.

von Boa Constructor (Gast)


Lesenswert?

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,

von Boa Constructor (Gast)


Lesenswert?

.....
also dann Strings via Array vor-verketten und den (char)Pointer an 
Serial.print übergeben? Nur mal so dahingedacht, bin kein c Profi

von Stefan F. (Gast)


Lesenswert?

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.

von Boa Constructor (Gast)


Lesenswert?

OK. Also bleibt es so, wie gehabt

Boa Constructor schrieb:
> 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 
3
> mit Zeilenumbruch
4
> #define SPT(text)    Serial.print(F(text))    // Text seriell ausgeben
5
> #define SPTLN(text)  Serial.println(F(text))  // Text seriell ausgeben 
6
> mit Zeilenumbruch
7
> #define SPTAB        Serial.print("\t")       // Tab ausgeben
8
>


Ich ging bisher davon aus, die vielen print wären das Problem. Aber wenn 
man nachrechnet, die Baudrate, dann ergibt sich der Rest.

von Boa Constructor (Gast)


Lesenswert?

Rolf M. schrieb:
> 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/

@ Rolf M. gute Seite, sehr aufschlußreich. danke

von Dirk B. (dirkb2)


Lesenswert?

Wie schnell ist dein Controller? ca. 10 MHz?

Der kann eine Million Funktionsaufruf pro Sekunde machen, bekommt aber 
nur 100 Zeichen in der Zeit weg.

von Stefan F. (Gast)


Lesenswert?

Boa Constructor schrieb:
> 
https://hackingmajenkoblog.wordpress.com/2016/02/04/the-evils-of-arduino-strings/
> @ Rolf M. gute Seite, sehr aufschlußreich. danke

Ich war derjenige, der den Artikel vorgeschlagen hat.

von Boa Constructor (Gast)


Lesenswert?

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 :))

von Stefan F. (Gast)


Lesenswert?

Boa Constructor schrieb:
> Dann danke an euch beide :))

Jetzt bin ich zufrieden :-)

von Cornelius (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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.
1
unsigned short function_freememory(char* buffer) {
2
    //
3
    void *p = 0;
4
    size_t size;
5
    for (size = RAMEND; size > 1; size -= 10) {
6
        p = malloc(size);
7
        if (p != 0) {
8
            break;
9
        }
10
    }
11
    if (p != 0) {
12
        free(p);
13
    }
14
    else {
15
        size=0;
16
    }
17
    return sprintf_P(buffer,PSTR("%5u"),size);
18
}

von Peter D. (peda)


Lesenswert?

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.

von Einer K. (Gast)


Lesenswert?

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.

von Einer K. (Gast)


Lesenswert?

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.

von Cornelius (Gast)


Lesenswert?

PeDa
>Man kann auch einfach plain C verwenden und mit strcat Strings
>aneinander kopieren. Dann wird kein unnützer Speicher alloziert.

Das ist schon wahr, aber die Arduino-String-Funktionen sind so 
unglaublich bequem:
https://www.arduino.cc/reference/en/language/variables/data-types/stringobject/

Wirklich, bis man das alles mit C zusammen hat, ist man eine Weile 
unterwegs.

Ich vermute, Arduino-String ist ein Versuch, sich der Java-API zu 
nähern:
https://www.dpunkt.de/java/Referenz/Das_Paket_java.lang/68.html

von Stefan F. (Gast)


Lesenswert?

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?

von Einer K. (Gast)


Lesenswert?

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++"

von Einer K. (Gast)


Lesenswert?

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.

von Roth (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Da ist unsigned sicherlich gänzlich falsch.

Na also. Klappt doch.
Weiter so.

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
Noch kein Account? Hier anmelden.