Was bedeutet const
wirklich? Schreibgeschützt scheint seine Bedeutung für mich zusammenzufassen, aber ich bin nicht sicher, ob ich recht habe.
Wenn sich schreibgeschützt und const
unterscheiden, kann mir dann jemand sagen, warum?
Anlass für diese Frage war diese Antwort wobei er angibt, dass const
"nur" in C schreibgeschützt bedeutet. Ich dachte, das ist allconst
, unabhängig davon, ob es C oder C++ war. Was meint er?
Für eine Antwort auf die spezifischen Unterschiede in const
in C vs. C++ habe ich eine neue Frage erstellt: Wie unterscheidet sich "const" in C und C++? gemäß dem Vorschlag von R. ...
Wenn Sie eine Variable als const
deklarieren, geben Sie dem Compiler an, dass Sie nicht beabsichtigen, diese Variable zu ändern. Aber das bedeutet nicht, dass andere es nicht haben! Es wird lediglich eine gewisse Optimierung ermöglicht und durch einen Kompilierungsfehler benachrichtigt (Beachten Sie, dass es sich hauptsächlich um Kompilierungsfehler handelt, während const == ReadOnly
Laufzeitfehler bedeuten würde).
const
bedeutet nicht read only, da Sie const volatile
schreiben können, dh es könnte sich jederzeit ändern, aber ich habe nicht die Absicht, es zu ändern.
BEARBEITEN: Hier ist ein klassisches Beispiel: Angenommen, ich schreibe den Code, der die aktuelle Zeit von einem speicherzugeordneten Port liest. Beachten Sie, dass RTC dem Speicher DWORD 0x1234 zugeordnet ist.
const volatile DWORD* now = (DWORD*)0x1234;
Es ist const
, weil es sich um einen schreibgeschützten Port handelt, und es ist volatile
, weil ich es jedes Mal, wenn ich es lese, ändert.
Beachten Sie auch, dass viele Architekturen globale Variablen effektiv als const
als schreibgeschützt deklarieren, da sie von UB geändert werden müssen. In diesen Fällen manifestiert sich UB als Laufzeitfehler. In anderen Fällen wäre es eine echte UB :)
Hier ist eine gute Lektüre: http://publications.gbdirect.co.uk/c_book/chapter8/const_and_volatile.html
Der Compiler lässt keine Änderungen zu, die als const
deklariert sind. Es ist wie du sagst.
Es wird meistens in Funktionsprototypen verwendet, um den Benutzer darüber zu informieren, dass eine Funktion dieses oder jenes nicht berührt, wenn Zeiger übergeben werden. Es funktioniert auch als eine Art Ausfallsicherheit für Sie.
Viele Leute sagen Ihnen, dass const
bedeutet, dass Sie es nicht ändern können. Das ist offensichtlich falsch. const
kann trivial weggeworfen werden. Beachten Sie diesen Ausschnitt:
void foo(const int *somevalue)
{
int *p = (int*) somevalue;
*p = 256; // OMG I AM EVIL!!!!11
}
Ihr Compiler wird Sie nicht davon abhalten. Was ist also der Zweck von const
? Ich würde es eher einen Vorschlag nennen. Es erinnert Sie daran, wenn Sie Funktionsprototypen des Vertrags betrachten, die Ihre Funktionen erwarten. Ihr Compiler wird Sie anschreien, wenn Sie ihn unvorsichtig brechen. (Aber nicht, wenn Sie es absichtlich brechen, wie bei dem oben genannten Cast.)
In einigen Fällen bricht der Standard absichtlich const
. Beachten Sie beispielsweise die Rückgabewerte von strstr
: Per Definition wird ein gewisser Versatz in den von Ihnen angegebenen const
-Puffer zurückgegeben. Der zurückgegebene Wert ist jedoch nicht const
. Warum? Nun, dies würde mit dem Rückgabewert von strstr
in einem Nicht-const
-Puffer bedeutungsvoll brechen.
Zwei Byte für Byte identisch (außer für die Kommentare), minimale Fallbeispiele ...
In C wird zuerst eine Warnung ausgegeben ...
/* Funktion, die einen Zeiger auf ein Array von zwei Nur-Lese-Ganzzahlen. */ void a (const int (* parray) [2]); void b (void) { int Array [2] = {1,2}; const int crray [2] = {1,2}; /* C behält sich das Recht vor, dies an einem schreibgeschützten Ort zu speichern. */ a (& Array); /* Warnung: Übergeben von Argument 1 von 'a' vom nicht kompatiblen Zeigertyp */ ein (& crray); /* OK!*/ }
Nun ist dasselbe in C++ ... g ++ ist ziemlich zufrieden damit.
// Funktion, die einen Zeiger auf ein Array // von zwei Ganzzahlen verwendet, die nicht geändert werden sollen. // (Wenn wir nicht die Konstante wegwerfen ;-P) Void a (const int (* parray) [2]); . int Array [2] = {1,2}; const int crray [2] = {1,2}; a (& Array); // C++ hat damit kein Problem . ein (& crray); // OK! }
const char * hello_1{ "Hello!" };
const char hello_2[]{ "Hello!" };
char * ptr{};
// take away the const-nes
// ptr = (char *)hello_1;
// *ptr = '*'; <-- write access violation
// hello_1 is in a read only memory
// take away the const-nes
ptr = (char *)hello_2;
*ptr = '*'; // <-- OK
// hello_2 is modifiable
Zeiger zeigen auf Speicher, und char *
zeigt auf Speicher in dem schreibgeschützten Datensegment. Der Unterschied zwischen char *
und char []
besteht darin, dass, während beide im Datensegment auf die gleiche Weise deklariert werden, char []
als lesbar behandelt wird, da es bei Verwendung auf den Stack verschoben wird.