Fehlermeldung: C++ forbids converting a string constant to char*

Hallo,

ich verwende eine Klasse um in einer Funktion Daten von verschiedenen anderen ESP32-Geräten zu bekommen. Ich verwende einen Pointer zur Übergabe der IP-Adresse and die client connect - Funktion. Im Grunde funktioniert alles , aber ich bekomme einen Warnhinweis beim Compilieren.
Ich bin nicht ganz so fit mit den Pointern. Wie kann ich das besser machen bzw so lösen, dass der Compiler keinen Warnhinweis ausgibt? Kann mir jemand von euch weiterhelfen?

(es gibt hier nur die relevanten Auszüge, weil der gesamte Code ca 5000 Zeilen lang ist)

Fehlermeldung bzw Warnhinweis des Compilers: (genau genommen ist es nur ein Warnhinweis - der Code wird erstellt und ausgeführt)

In file included from C:\Users\Peter\_docs\Arduino_ESP_main\Code\_Projekt Controlcenter\ESP_CoC_V3_3\ESP_CoC_V3_3.ino:132:
C:\Users\Peter\_docs\Arduino_ESP_main\Code\_Projekt Controlcenter\ESP_CoC_V3_3\espdef.h:49:16: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
   char* ip_a = "192.168.178.021";                       
                ^~~~~~~~~~~~~~~~~
C:\Users\Peter\_docs\Arduino_ESP_main\Code\_Projekt Controlcenter\ESP_CoC_V3_3\espdef.h:53:16: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
   char* ip_b = "192.168.178.022";
                ^~~~~~~~~~~~~~~~~

... und die relevanten Code-Teile:

Definition der Parameter abhängig vom Gerät im Netzwerk:

#if ESP_DEVICE == 20   // KHz
// =============================================
 
  // -------- der eigene ESP ----------------
  const IPAddress ip(192,168,178,20);
  const char* myhostname = "KG-Heizung";                 // auch am Router sichtbar
  const String smyname = "KHz";                         // muss EG, DG, KGr oder KWr , weil damit Auswahlen getroffen werden
  const bool freieaccesspointwahl = 0;                  // 0 = fixer accesspoint  ;  1 = freie wahl
  const byte macaccesspoint[] = {0x2C, 0x3A, 0xFD, 0xBB, 0x1E, 0x93}; 

  // ------------ Interface - getData ----------      
  const String sinterface_a = "EG => KHz";
  char* ip_a = "192.168.178.021";                       // const char* geht nicht;   Host/Server ESP für Datenabfrage
  const byte anzahlwerte_a = 44;                        // if anzahlwerte == 0,  dann keine Schnttstelle

  const String sinterface_b = "DG => KHz";
  char* ip_b = "192.168.178.022";
  const byte anzahlwerte_b = 29;                        // 29 .. 

  
// ============================================
#endif

Definition der Klasse und der dazugehörigen Objekte:

class cGetDataInterface {                                   // die Klasse für die GetDataroutine
  public:
    cGetDataInterface (String sif, char* ip, byte anzahl) {    // constructor definiert das Variablenset für den Start
      sinterfacename = sif;
      ipsource = ip;
      anzahlwerte = anzahl;
    }; 
    String sinterfacename;                      // Name der Schnittstelle
    char* ipsource;                             // const char* oder char[16] funktioniert nicht - es muss ein char* sein
    byte anzahlwerte;                           // Anzahl Werte der Schnittstelle
    int16_t getdatazeit;                        // Zeit in ms bis die Daten empfangen wurden
    unsigned long getdatastartzeit;             // Startzeit für Zeitmessung getdatazeit
    int16_t getdatazeitzulange;                 // zählt wie oft die getdatazeit bereits zu lange war
    int16_t getdatafehler;                      // zählt die getdatafehler der schnittstelle - wird auf Null gesetz beim nächsten  erfolgreichen Datanaustausch
    int16_t getdatafehlergemeldet;              // verhindert Mehrfachmeldungen bei getdatafehler
    String swerte[maximalfeldergetdata];        // liefert die Daten des Empfangsstring in die einzelnen Datenfelder (swerte[x])
  };

cGetDataInterface espa (sinterface_a, ip_a, anzahlwerte_a);     // Definition der 2 Objekte der Klasse
cGetDataInterface espb (sinterface_b, ip_b, anzahlwerte_b);

Verwendung in der Funktion:

 if (WiFi.status() == WL_CONNECTED) {                    //   3 = connected , 1 = not connected
    if (wifinotconnectedgemeldet == true) Meldung("WiFi wieder verbunden", 'g');

    wifistatusconnect = true;
    wifinotconnectedgemeldet = false;
    WiFiClient client;

    if(!client.connect(espx.ipsource, 80)) {
      sdata_esp = ("xx|xx|xx|xx|xx|xx|xx|xx|xx|");        // x auf der ersten Stelle - d.h. bei der Stringaufteilung wird der String mit  Zahl/Muster gefüllt = ungültig
      getdatafehlergesamt ++;
      espx.getdatafehler ++;
      if (espx.getdatafehler >= getdatafehlertoleranz) {
        for (int i = 0; i < espx.anzahlwerte; i++) espx.swerte[i] = swertedatenfehler;    // lässt die Werte 4 x gleich, bevor die letzten gültigen WErte überschrieben werden
        if (espx.getdatafehlergemeldet == 0) { 
          text = "GetDataFehler: " + espx.sinterfacename + ", DF:" + String(espx.getdatafehler);
          Meldung(text, 'o');
          espx.getdatafehlergemeldet = 1;
        }
      }
      if (espx.getdatafehler > 15 && espx.getdatafehlergemeldet < 2) {       // Meldung getdatafehler DF16
        espx.getdatafehlergemeldet = 2;        
        text = "GetDataFehler: " + espx.sinterfacename + ", DF:" + String(espx.getdatafehler);
        Meldung(text, 'r');
      }
    ledcWrite(pwmchannelgetdataled, 0);
      return espx;                                // Rückgabe des gesamten Objektes 
    }
    
    client.print(String("GET ") + sdatenurl + " HTTP/1.1\r\n" + "Host: " + espx.ipsource + "\r\n" + "Connection: close\r\n\r\n");   //holt sich von /data vom sendenden Server die Daten
    unsigned long letzterconnect = millis();
    while (!client.available() && millis() - letzterconnect < 1500) {   // war vor dem 6.3.24  5000 -  evtl probleme bei schlechter WLAN-Verbindung , weil dan alles relativ lange dauert
      delay(5);
    }
    while (client.available()) {
      String line = client.readStringUntil('\r');                     // einlesen des Strings vom sendenden ESP - Sring wird bis zum /r eingelesen (Carriage Return)
      if (line != "") sdata_esp = line;                               // wenn ein inhalt im Empfangsstring line ist, wird der Inhalt übergeben 
    }
    if (datenanalyse == true) Serial.println("DATEN: empfangener String: " + sdata_esp);   
  }         // end if (WiFi.status() == WL_CONNECTED)
 

   const char* ip_a = "192.168.178.021";   // flash         

oder

   char ip_a[] = "192.168.178.021"; // flash + RAM
1 Like

Danke .. hab beide Methoden versucht und beide funktionieren - zur 2. habe ich noch eine Frage:

das mit const char* funktioniert, wenn ich auch in der Klasse die Definitionen auf const char setze (sowohl im header der classe als auch in der Variablendefinition:

class cGetDataInterface {                                   // die Klasse für die GetDataroutine
  public:
    cGetDataInterface (String sif, const char* ip, byte anzahl) {    // constructor definiert das Variablenset für den Start
      sinterfacename = sif;
      ipsource = ip;
      anzahlwerte = anzahl;
    }; 
    String sinterfacename;                      // Name der Schnittstelle
    const char* ipsource;                            

... und auch die 2. Methode mit dem Array ( char ip_a[] )funktioniert - da kann die Klassendefinition mit char* bestehen bleiben . Ist das deshalb weil ein Array auch im Grunde ein Zeiger auf das erste Datenfeld des Arrays ist?

Das Array "zerfällt" zu einem Zeiger, wenn man die implizite Konvertierung einfordert.
Dabei geht allerdings die Arraygröße verloren, was in diesem Fall nicht stört, aber sonst auch mal unangenehm werden kann.

1 Like

da würde ich erst mal nachsehen, welche Interfaces die Funktionen am ESP32 anbieten, und evtl. ist eine Klasse des Typs class IPAddress sowieso besser als ein char*

arduino-esp32/cores/esp32/IPAddress.h at master · espressif/arduino-esp32 · GitHub


Das ist eine ganz schlechte Ausrede. Dann macht man halt ein MRE um zu zeigen worum es geht. Das hilft meist auch einem selber sich auf das eigentliche Problem zu konzentrieren.

... das Problem wurde bereits gelöst , auch ohne dass man den gesamten Code postet. (war also KEINE Ausrede !!)

nur weil dir jemand entgegengekommen ist und dir dennoch was geliefert hat - bleibt es dennoch eine Ausrede.
Man postet vollständigen Code.
Punkt.

Danke auch für deinen Input - aber es funktioniert und das reicht mir vorerst mal.

Anbei mal ein Screenshot - das macht in dem fall echt keinen Sinn den Code aus allen Tabs zu laden - es reichen die relevanten Teile

Ein leeres void loop() {} kann man sich schonmal sparen. aber sonst richtig.

Vollständiger Code muss oft nicht länger als 5 .. 10 Zeilen sein.

"Den gesamten Code" will eigentlich keiner sehen, da kriegt man dann nur irrelevante Tips, z.B. dass man heutzutage constexpr statt #define schreibt und ähnliche (richtige aber --wie gesagt-- irrelevante) Tips.

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