Was bedeutet dieser Fehler? Ich kann es in keiner Weise lösen.
Warnung: Veraltete Konvertierung von String-Konstante zu 'char *' [-Wwrite-strings]
Was bedeutet dieser Fehler? Ich kann es in keiner Weise lösen.
Warnung: Veraltete Konvertierung von String-Konstante zu 'char *' [-Wwrite-strings]
Antworten:
Wie es meine Gewohnheit ist, werde ich ein paar technische Hintergrundinformationen zum Warum und Woher dieses Fehlers geben.
Ich werde vier verschiedene Arten der Initialisierung von C-Strings untersuchen und die Unterschiede zwischen ihnen herausfinden. Dies sind die vier in Frage kommenden Möglichkeiten:
char *text = "This is some text";
char text[] = "This is some text";
const char *text = "This is some text";
const char text[] = "This is some text";
Aus diesem Grund möchte ich den dritten Buchstaben "i" in "o" ändern, um daraus "Thos is some text" zu machen. Dies könnte in allen Fällen (Sie würden denken) erreicht werden durch:
text[2] = 'o';
Schauen wir uns nun an, was die einzelnen Deklarationsarten der Zeichenfolge bewirken und wie sich diese text[2] = 'o';
Anweisung auf die Dinge auswirken würde.
Zunächst wird die am häufigsten gesehen Art und Weise: char *text = "This is some text";
. Was bedeutet das wörtlich? Nun, in C bedeutet es wörtlich "Erzeuge eine Variable, die aufgerufen text
wird und ein Lese- / Schreibzeiger auf dieses Zeichenkettenliteral ist, das im Nur-Lese- (Code-) Raum enthalten ist". Wenn Sie die Option -Wwrite-strings
aktiviert haben , wird eine Warnung angezeigt (siehe Frage oben).
Grundsätzlich bedeutet dies "Warnung: Sie haben versucht, eine Variable mit Lese- / Schreibzugriff auf einen Bereich zu setzen, in den Sie nicht schreiben können". Wenn Sie versuchen, das dritte Zeichen auf "o" zu setzen, versuchen Sie tatsächlich, in einen schreibgeschützten Bereich zu schreiben, und die Dinge werden nicht schön. Auf einem herkömmlichen PC mit Linux führt dies zu:
Segmentierungsfehler
Nun ist die zweite: char text[] = "This is some text";
. In C bedeutet dies wörtlich: "Erstellen Sie ein Array vom Typ" char "und initialisieren Sie es mit den Daten" Dies ist etwas Text \ 0 ". Die Größe des Arrays ist groß genug, um die Daten zu speichern." Das reserviert also tatsächlich RAM und kopiert zur Laufzeit den Wert "Dies ist etwas Text \ 0" hinein. Keine Warnungen, keine Fehler, vollkommen gültig. Und die richtige Vorgehensweise, wenn Sie die Daten bearbeiten möchten . Versuchen wir den Befehl auszuführen text[2] = 'o'
:
Das ist ein Text
Es hat perfekt funktioniert. Gut.
Nun ist die dritte Möglichkeit: const char *text = "This is some text";
. Wieder die wörtliche Bedeutung: "Erstellen Sie eine Variable mit dem Namen" text ", die ein schreibgeschützter Zeiger auf diese Daten im Nur-Lese-Speicher ist." Beachten Sie, dass sowohl der Zeiger als auch die Daten jetzt schreibgeschützt sind. Keine Fehler, keine Warnungen. Was passiert, wenn wir versuchen, unseren Testbefehl auszuführen? Das können wir nicht. Der Compiler ist jetzt intelligent und weiß, dass wir versuchen, etwas Schlechtes zu tun:
Fehler: Zuweisung des schreibgeschützten Speicherorts '* (Text + 2u)'
Es wird nicht einmal kompiliert. Der Versuch, in den Nur-Lese-Speicher zu schreiben, ist jetzt geschützt, da wir dem Compiler mitgeteilt haben, dass unser Zeiger auf den Nur-Lese-Speicher gerichtet ist. Natürlich ist es nicht hat Speicher zu schreibgeschützt zu zeigen, aber wenn Sie darauf zeigen Speicher - Lese-Schreib (RAM) , dass der Speicher noch nicht geschrieben , um durch den Compiler geschützt werden.
Schließlich die letzte Form: const char text[] = "This is some text";
. Auch hier []
ordnet es wie zuvor ein Array im RAM zu und kopiert die Daten hinein. Dies ist jedoch jetzt ein schreibgeschütztes Array. Sie können nicht darauf schreiben, da der Zeiger darauf als markiert ist const
. Der Versuch, darauf zu schreiben, führt zu:
Fehler: Zuweisung des schreibgeschützten Speicherorts '* (Text + 2u)'
Also, eine kurze Zusammenfassung, wo wir sind:
Dieses Formular ist vollständig ungültig und sollte unter allen Umständen vermieden werden. Es öffnet die Tür für alle Arten von schlechten Dingen:
char *text = "This is some text";
Dieses Formular ist das richtige, wenn Sie die Daten bearbeitbar machen möchten:
char text[] = "This is some text";
Dieses Formular ist das richtige, wenn Sie Zeichenfolgen möchten, die nicht bearbeitet werden können:
const char *text = "This is some text";
Diese Form scheint RAM verschwenderisch zu sein, hat aber ihre Verwendung. Am besten vorerst vergessen.
const char text[] = "This is some text";
PROGMEM
, PSTR()
oder F()
. So const char text[]
verwendet nicht mehr RAM als const char *text
.
(const char *)(...)
Casting zu definieren . Kein wirklicher Effekt, wenn das Board es nicht benötigt, aber eine große Ersparnis, wenn Sie dann Ihren Code auf ein Board portieren, das dies tut.
Um die ausgezeichnete Antwort von Makenko zu erläutern, gibt es einen guten Grund, warum der Compiler Sie davor warnt. Machen wir eine Testskizze:
char *foo = "This is some text";
char *bar = "This is some text";
void setup ()
{
Serial.begin (115200);
Serial.println ();
foo [2] = 'o'; // change foo only
Serial.println (foo);
Serial.println (bar);
} // end of setup
void loop ()
{
} // end of loop
Wir haben hier zwei Variablen, foo und bar. Ich ändere eine davon in setup (), sehe aber, was das Ergebnis ist:
Thos is some text
Thos is some text
Sie haben sich beide umgezogen!
In der Tat, wenn wir uns die Warnungen ansehen, sehen wir:
sketch_jul14b.ino:1: warning: deprecated conversion from string constant to ‘char*’
sketch_jul14b.ino:2: warning: deprecated conversion from string constant to ‘char*’
Der Compiler weiß, dass dies zweifelhaft ist, und es ist richtig! Der Grund dafür ist, dass der Compiler (vernünftigerweise) erwartet, dass sich die String-Konstanten nicht ändern (da es sich um Konstanten handelt). Wenn Sie also "This is some text"
in Ihrem Code mehrmals auf die Zeichenfolgenkonstante verweisen, ist es zulässig , allen denselben Speicher zuzuweisen . Wenn Sie jetzt eine ändern, ändern Sie alle!
*foo
und *bar
Verwendung unterschiedlicher String- "Konstanten" dies verhindern? Inwiefern unterscheidet sich dies auch davon, überhaupt keine Zeichenfolgen zu setzen, wie zum Beispiel char *foo;
:?
new
, strcpy
und delete
).
Beenden Sie entweder den Versuch, eine Zeichenfolgenkonstante an die Stelle zu übergeben, an der eine Funktion a annimmt char*
, oder ändern Sie die Funktion so, dass sie a annimmt const char*
.
Zeichenfolgen wie "Zufallszeichenfolgen" sind Konstanten.
Beispiel:
void foo (char * s)
{
Serial.println (s);
}
void setup ()
{
Serial.begin (115200);
Serial.println ();
foo ("bar");
} // end of setup
void loop ()
{
} // end of loop
Warnung:
sketch_jul14b.ino: In function ‘void setup()’:
sketch_jul14b.ino:10: warning: deprecated conversion from string constant to ‘char*’
Die Funktion foo
erwartet ein Zeichen * (das sie daher ändern kann), aber Sie übergeben ein Zeichenfolgenliteral, das nicht geändert werden sollte.
Der Compiler warnt Sie davor. Wenn es veraltet ist, wird es möglicherweise in einer zukünftigen Compilerversion zu einem Fehler.
Lösung: Lassen Sie foo einen const char * nehmen:
void foo (const char * s)
{
Serial.println (s);
}
Ich verstehe es nicht. Meinst du, kann nicht geändert werden?
In älteren Versionen von C (und C ++) können Sie Code wie in meinem obigen Beispiel schreiben. Sie könnten eine Funktion (wie foo
) erstellen, die etwas druckt, das Sie übergeben haben, und dann eine wörtliche Zeichenfolge (z. B. foo ("Hi there!");
) übergeben.
Eine Funktion, die char *
als Argument nimmt, darf jedoch ihr Argument ändern (dh Hi there!
in diesem Fall ändern ).
Sie könnten zum Beispiel geschrieben haben:
void foo (char * s)
{
Serial.println (s);
strcpy (s, "Goodbye");
}
Durch die Übergabe eines Literal haben Sie dieses Literal jetzt möglicherweise so geändert, dass "Hi there!" ist jetzt "Auf Wiedersehen", was nicht gut ist. Wenn Sie eine längere Zeichenfolge kopieren, werden möglicherweise andere Variablen überschrieben. Oder bei einigen Implementierungen wird eine Zugriffsverletzung angezeigt, weil "Hi there!" Möglicherweise wurde es in den schreibgeschützten Arbeitsspeicher (RAM) gestellt.
Daher wird diese Verwendung von den Compilern nach und nach abgelehnt , sodass Funktionen, an die Sie ein Literal übergeben, dieses Argument als deklarieren müssen const
.
can not
modifiziert werden?
Ich habe diesen Kompilierungsfehler:
TimeSerial.ino:68:29: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
if(Serial.find(TIME_HEADER)) {
^
Bitte ersetzen Sie diese Zeile:
#define TIME_HEADER "T" // Header tag for serial time sync message
mit dieser Zeile:
#define TIME_HEADER 'T' // Header tag for serial time sync message
und die zusammenstellung geht gut.