String Concat auf ESP8266

Servus zusammen,

ich baue in der untenstehenden Methode ein CSV zusammen. Jedoch funktioniert, aus welchen Gründen auch immer, die Stringverkettung nicht.

String generateCsvFromCollectedData(double collectedHoursPerSide[]){
  double collectedValue = collectedHoursPerSide[0];
  String csv = "top;" + String(collectedValue,2) + ";";
return csv;
}

Der Sketch kompiliert zwar, zur Laufzeit schaut es aber so aus als würde der ESP in einer Schleife abstürzen und neustarten.

Aus dem Serial Monitor lese ich folgendes:

--------------- CUT HERE FOR EXCEPTION DECODER ---------------

Exception (28):
epc1=0x402015c7 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000004 depc=0x00000000

>>>stack>>>

ctx: cont
sp: 3ffffcf0 end: 3fffffd0 offset: 0150
3ffffe40:  00000000 00000000 3ffeec10 3ffeecf4  
3ffffe50:  3fffdad0 00000010 3ffeec10 3ffeecf4  
3ffffe60:  3fffdad0 00000001 3fff0464 40203dea  
3ffffe70:  3ffffedc 00000000 00000000 3ffeecf4  
3ffffe80:  3fffdad0 3ffee8f8 3fff0464 40202329  
3ffffe90:  00000000 3ffee8f8 3ffee8a0 40203aa8  
3ffffea0:  40105fc1 00000000 00000000 0019001f  
3ffffeb0:  00000000 3ffeeccc 3ffee8b4 402057f0  
3ffffec0:  00000000 0000e107 00000000 00000001  
3ffffed0:  00000000 00000000 3ffee8a0 3ffeecf4  
3ffffee0:  3fffdad0 3ffee8d4 3ffee8a0 402042ce  
3ffffef0:  4020cd64 00000000 00001388 00fb2784  
3fffff00:  00000000 00000000 3fff041c 00000000  
3fffff10:  3fffdad0 0000d936 000007d0 3ffeecf4  
3fffff20:  3fffdad0 00000000 3ffeecc8 402043cd  
3fffff30:  00000024 00000002 0000000d 00000000  
3fffff40:  0000d933 41ce073a 00000000 00000000  
3fffff50:  00000000 00000001 00000001 00000004  
3fffff60:  00000000 0000d933 bb0bb3fd bc0bb3fd  
3fffff70:  3b63047c 00000000 00000001 00000000  
3fffff80:  00000000 00000000 0000d933 40054f24  
3fffff90:  3f859d99 4118590c 00000000 3ffeecf4  
3fffffa0:  3fffdad0 00000000 3ffeecc8 3ffeecf4  
3fffffb0:  00000000 00000000 3ffeecc8 40209e18  
3fffffc0:  feefeffe feefeffe 3fffdab0 40100f75  
<<<stack<<<

--------------- CUT HERE FOR EXCEPTION DECODER ---------------

Ich habe bereits Lösungsversuche mittels std::string sowie Verkettung ohne Operator und mit , versucht. Bisher jedoch ohne Erfolg. Ich vermute dass der + Operator hier als Binaryoperator interpretiert wird, komme an dieser Stelle jedoch selbstständig nichtmehr weiter.

Über Erläuterungen und Lösungen für mein Problem wäre ich sehr dankbar.

Danke Euch und beste Grüße

Installiere Dir mal den Exceptiondecoder und schau was der Dir sagt.
Ansonsten kann mit dem Fragment keiner etwas anfangen.

Gruß Tommy

Wenn du einen vollständigen Sketch rund um deine Funktion baust dann kann man dir vermutlich auch eine grundsätzlich fehlerfreie Variante zeigen.

Besser wäre es aber, du beschreibst, was am Ende mit dem CSV genau passieren soll und vieleicht findet sich dann eine Variante die ganz ohne String Objekten auskommt.

No it isn't.

Without seeing in which way you actually call the function it is not possible for me to see the issue.

There isn't anything 'really' wrong with the function itself, though usingikt may result in memory fragmentation at some point. What is returned is the pointer to the String object, which upon time of return still contains the data but pretty much goes out of scope straight away.
So if you do

String concatCsv = generateCsvFromCollectedData(collectedHoursPerSide);  // or whatever argument you pass

or

Csv += generateCsvFromCollectedData(collectedHoursPerSide);  // or whatever argument you pass

It is all good,

There a a chance though that it has not much to do with the String side of things but rather with argument you pass.
so for verification do

String generateCsvFromCollectedData(double collectedHoursPerSide[]){
  double collectedValue = collectedHoursPerSide[0];
  String csv = "top;" + ";";
return csv;
}

which should tell you where the issue is.

Hallo @kireznieh ,

herzlich willkommen im Arduino-Forum.
Gut gemacht den code als Code-Section zu posten.

Trotzdem wie schon @noiasca angemerkt
immer kompletten Sketch posten.
Auch dann wenn der Sketch 3000 Zeilen haben sollte.

Es ist viel besser gleich alle Infos zur Verfügung zu haben als bröckchenweise.

Mit Exception-Decoder ist das hier gemeint.
Damit kann man für einen Sourcecode herausfinden wo im Code die Exception auftritt.
Auch dafür wäre es nützlich exakt den kompletten Sketch zu haben bei dem die Exception auftritt

vgs

Ach entshuldigung, it hatte die ganze pagina von Google uberstezen lassen.

Hallo,

Das von dir gepostete Snippet liefert den folgenden Fehler zur Compiletime:

error: invalid operands of types 'const char [5]' and 'const char [2]' to binary 'operator+'

ich kann mit 100% Sicherheit sagen dass das Problem bei der Konvertierung des doubles in einen String und dessen Verkettung liegt.
Folgendermaßen funktioniert der Sketch und gibt mir wie erwartet "Hallo Welt" zurück.
Auch Exception sehe ich dann nicht.

String generateCsvFromCollectedData(double collectedHoursPerSide[]){
  double collectedValue = collectedHoursPerSide[0];
  //String csv = "top;" + ";";
  return "Hallo Welt";
}

Der Exceptiondecoder sagt: Exception 28: LoadProhibited: A load referenced a page mapped with an attribute that does not permit loads

Ich packe den Output der Methode in den Body eines Http Responses und schicke ihn an den Client. Das funktioniert auch solange ich nur Strings zurückschicke. Sobald ich versuche mit einem double zu verketten tritt die oben genannte Problematik auf.

Das ist auch keine Verkettung von zwei Strings, sondern ein undefinierter operator+ zwischen zwei const char*, bzw. einem const char[5] und einem const char[2]

Und ein + zwischen einem text ( const char*) und einem double gibt es auch nicht.

Wusstest du, dass "hello world" + 4 als Ergebnis "o world" ergibt? Das ist zwar erlaubt, aber auch keine Verkettung.

Tip: Strings kann man verketten, und vieles kann man in einen String verwandeln, indem man es an einen String- Konstruktor als Parameter übergibt.

double x = 3.4567;
String s = String(x); // "3.46"
s = s+String(x,5); //  "3.463.45670"

String und const char* kann man leider verketten, aber das verwirrt dich offensichtlich nur.

Hallo,
danke für den Tipp. Wie aus meinem Ausgangspost hervorgeht habe ich die Konvertierung mittels String() schon probiert.
Hast du eine weitere Idee?

SafeString.h

Verkettet alles

// SafeStrings are based on array of chars
// SafeStrings offer almost the same comfort as Strings
// but avoid some dis-advantages of variable-type String
// the name SafeString is PROGRAM They are safe to use

// with the alternatives "String" must not always but CAN
// eat up memory over time which will make the code crash

// with zero-terminated array of chars (c_string)
// you have to take care of boundary checking yourself
// otherwise your code will start to behave weird and this kind of bug is very hard to find
// you can read more about this here https://www.forward.com.au/pfod/ArduinoProgramming/ArduinoStrings/index.html#safestring
// and here https://hackingmajenkoblog.wordpress.com/2016/02/04/the-evils-of-arduino-strings/

// very basic demo-code to show how to declare a SafeString-variable
// and how to assign text to them

// as a personal convention I use the suffix "_SS" to indicate
// THIS IS A SAFESTRING-VARIABLE
// but you can name it whatever you like

#include "SafeString.h"
createSafeString(myTitle_SS, 64);  // reserve 64 bytes for the SafeString-variable
createSafeString(myString_SS, 64); // reserve 64 bytes for the SafeString-variable
createSafeString(myExtraloongString_SS, 128); // reserve 128 bytes for the SafeString-variable

int myInteger = -1234;
float myFloat = -987.009;
float myFloat2 = -12345.6789;
float myFloat3 = -1234.567;


void setup() {
  Serial.begin(115200);
  Serial.println( F("Setup-Start") );
  Serial.println();

  myString_SS = F("fixed text directly assigned");
  Serial.print( F(" #") ); // leading double-cross "#" to show where the string starts
  Serial.print(myString_SS);
  Serial.println(F("#") ); // trailing double-cross "#" to show where the string REALLY ends


  myTitle_SS = F("content of an integer:");
  myString_SS = myInteger;

  Serial.println(myTitle_SS);
  Serial.print( F(" #" )); // leading double-cross "#" to show where the string starts
  Serial.print(myString_SS);
  Serial.println( F("#") ); // trailing double-cross "#" to show where the string REALLY ends


  myTitle_SS = F("content of a float:");
  myString_SS = myFloat;

  Serial.println(myTitle_SS);
  Serial.print( F(" #" )); // leading double-cross "#" to show where the string starts
  Serial.print(myString_SS);
  Serial.println( F("#") ); // trailing double-cross "#" to show where the string REALLY ends

  myTitle_SS = F("you can append more text with the +=-operator ");
  myString_SS = F("text ");
  myString_SS += myInteger;
  myString_SS += F(" ,");
  myString_SS += myFloat;

  Serial.println(myTitle_SS);
  Serial.print( F("result: #" )); // leading double-cross "#" to show where the string starts
  Serial.print(myString_SS);
  Serial.println( F("#") ); // trailing double-cross "#" to show where the string REALLY ends

  myString_SS += F(" ,");
  myString_SS += myFloat2;

  myString_SS += F(" ,");
  myString_SS += myFloat3;

  Serial.println(myTitle_SS);
  Serial.print( F("result: #" )); // leading double-cross "#" to show where the string starts
  Serial.print(myString_SS);
  Serial.println( F("#") ); // trailing double-cross "#" to show where the string REALLY ends

  Serial.println( F(" now let's try to assign wayyyyyy too many characters 012345678900123456789001234567890012345678900123456789001234567890") );
  myString_SS  = "";
  myString_SS += F(" now let's try to assign wayyyyyy too many characters 012345678900123456789001234567890012345678900123456789001234567890");
  Serial.print( F("result: #" )); // leading double-cross "#" to show where the string starts
  Serial.print(myString_SS);
  Serial.println( F("#") ); // trailing double-cross "#" to show where the string REALLY ends

  Serial.println( F(" now let's try to add more and more characters at the end of the SafeString") );
  myString_SS  = "";
  for (byte i = 10; i < 64; i++) {
    myString_SS += i;
    Serial.print( F("result: #" )); // leading double-cross "#" to show where the string starts
    Serial.print(myString_SS);
    Serial.println( F("#") ); // trailing double-cross "#" to show where the string REALLY ends
  }

  Serial.println( F(" assigning a number of chars the SafeString can really hold") );
  myExtraloongString_SS = F("less than 64 characters");
  myString_SS  = myExtraloongString_SS;
  Serial.print( F("result: #" )); // leading double-cross "#" to show where the string starts
  Serial.print(myString_SS);
  Serial.println( F("#") ); // trailing double-cross "#" to show where the string REALLY ends

  
  Serial.println( F(" assigning too many chars than the SafeString can really hold") );  
  Serial.println( F("more than 64 characters 1234567890123456789012345678901234567890123456789012345678901234567890") ); 
  //                                  10        20        30        40        50        60        70
  //                         1234567890123456789012345678901234567890123456789012345678901234567890
  myExtraloongString_SS = F("more than 64 characters 1234567890123456789012345678901234567890123456789012345678901234567890");
  myString_SS  = myExtraloongString_SS;
  Serial.print( F("result: #" )); // leading double-cross "#" to show where the string starts
  Serial.print(myString_SS);
  Serial.println( F("#") ); // trailing double-cross "#" to show where the string REALLY ends
}

void loop() {
}

welchen HTTP Client verwendest du? Für welchen Microcontroller programmierst du?

Lt. Titel ESP8266

Ich verstehe das unbedingte nutzen von String sowieso nicht. Die machen mehr Probleme, als sie lösen.

Entweder gleich sprintf/snprintf oder wenigstens etwas, das sicher gegen Fragmentieren ist wie PString oder das SafeString, das StephanL38 vorschlägt.
Beide belegen keinen RAM dynamisch.

Gruß Tommy

Entschuldigung, die einfachste Lösung, die ich für Sie habe, ist so etwas.

double colV = 1234567.891023;

void setup() {
  Serial.begin(115200);
  delay(500);
  Serial.println();
  Serial.println("Started !!");
  Serial.println(generateCsvFromCollectedData(colV));

}

void loop() {
}

String generateCsvFromCollectedData(double collectedValue) {
  String csv = "top;";
  csv += String(collectedValue, 2);
  csv += ";";
  return csv;
}

Dies lässt sich ohne Probleme kompilieren und ausführen.

Den ESP8266WebServer

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.