Betrachten Sie diesen Code:
%Vor% Kompiliert fein mit gcc 4.9.2 -pedantic aber cl 18 (das von VS2013) mit Standardoptionen sagt warning C4090: 'function' : different 'const' qualifiers
in der memset-Zeile.
Jetzt ist caps
ein Zeiger auf einen Zeiger auf const char? Also der Zeiger selbst ist nicht const, daher sollte er in void*
ohne Probleme umgewandelt werden, denke ich, aber cl scheint automatisch const void*
daraus zu machen, was die Warnung erzeugt. Ist das eine korrekte Erklärung für das, was vor sich geht? Und das ist nicht standardmäßiges Verhalten, oder?
Der Compiler ist übereifrig (lesen als: Compiler Bug).
const char** caps
bedeutet, dass caps
ein Zeiger (der nicht konstant ist) auf einen anderen Zeiger (der auch nicht konstant ist) zu einem char
, der konstant ist. Das heißt, Sie versprechen, diese char
nicht durch Umleitungen zu ändern, die caps
überschreiten.
Das bedeutet, dass Sie mit dem Compiler formell den folgenden Vertrag abschließen:
caps
ändern. *caps
(das char*
, auf das caps
verweist) ändern. **caps
zu ändern (das char
, das *caps
zeigt auf (welches caps
auf Punkte zeigt)) über diese Kettenzeiger . Es wird nichts über irgendjemand anderen gesagt (z. B. Alias-Zeiger), der den Wert dieses Zeichens ändert.
const char ** Groß- / Kleinschreibung = malloc (sizeof (char *));
initialisiert caps
mit einem Wert, der legal ist. Für den Fall, dass malloc
fehlschlägt, ist dieser Wert ein Null-Zeiger, aber auch dies ist aus Sicht der Sprache im Allgemeinen vollkommen legal (obwohl dies zum Absturz des folgenden memset
führen würde). In C ++ müssten Sie das void*
, das von malloc
zurückgegeben wird, explizit umwandeln, aber C erlaubt das ganz gut.
lässt meine Haare aufstehen (ich bin ein C ++ - Programmierer), aber aus der Sicht der C-Sprache ist es trotzdem eine vollkommen legale Angelegenheit.
Was es tut ist überschreiben die bisher zugewiesenen, aber nicht initialisiert (und von caps
gezeigt) Speicherblock, der den zweiten Zeiger mit einer Anzahl von Null Bytes gleich der Größe eines Zeigers enthält (a char
Zeiger, als es passiert).
Die Bibliotheksfunktion memset
, die eine nicht-konstante void*
übernimmt, füllt einfach die Anzahl der Bytes, die Sie fragen (hier sizeof(char*)
) mit dem von Ihnen angegebenen Wert (hier: Null). Sie müssen sich nicht um den Vertrag kümmern, den Sie mit dem Compiler abgeschlossen haben. Aber trotzdem verletzt es keine Regeln. Es überschreibt den Zeiger, nicht den angezeigten konstanten Wert.
Ja, es schreibt ein paar char
-Werte in etwas, das nicht ist ein Array von char
s (weshalb meine Haare aufstehen), aber gut ... das ist ... legal Es ist genau das, was memset
schließlich tun soll, und es wird höchstwahrscheinlich "wie erwartet funktionieren". Es wird den Zeiger auf ein Null-Bit-Muster setzen, das - abgesehen von einigen sehr seltenen exotischen Architekturen - einem Nullzeiger entspricht.
Zu keinem Zeitpunkt wurde der Speicherort **caps
geändert (oder auch nur darauf zugegriffen), also ist das alles vollkommen legal, Sie haben nichts von Ihren Versprechen gebrochen.
Die Warnung ist daher falsch.
Sie können keinen Zeiger auf eine Konstante ( const X *
) auf eine void *
umwandeln: das würde sein const
-Qualifikationsmerkmal verwerfen.
memset
muss diese Daten ändern, deshalb benötigt es einen void *
-Parameter und nicht einen const void *
-Parameter.
Wie Sie es geschrieben haben, bezieht sich const auf das Zeichen, nicht auf den Zeiger. Offensichtlich macht es wenig Sinn, Speicher nur zu reservieren, um zu deklarieren, dass er niemals modifiziert wird (was bedeutet, dass er niemals initialisiert wird).
Wenn der Zeiger selbst const sein soll, sollten Sie schreiben:
%Vor%Sie können den zweiten Zeiger auch const machen, aber das macht keinen Sinn, als das char const.
zu machenTags und Links c gcc visual-c++ pointers