C Frage: (const void *) vs (void *)

Lesezeit: 5 Minuten

Was ist der Unterschied zwischen const void * und void *? Unter welchen Umständen kann ein void-Zeiger auf a gecastet werden const void Zeiger?

Benutzer-Avatar
Jonathan Leffler

EIN const void * zeigt auf Speicher, der nicht geändert werden sollte.

EIN void * (nicht konstant) zeigt auf Speicher, der geändert werden könnte (aber nicht über die void *; Sie müssten es zuerst wirken).

Wenn Sie verwenden memmove()wird die Quelladresse umgewandelt const void *:

void *memmove(void *dst, const void *src, size_t nbytes);

Dies ist eine Veranschaulichung, wenn ein void-Zeiger in einen konstanten void-Zeiger umgewandelt werden kann. Grundsätzlich können Sie dies jederzeit tun (in eine Konstante konvertieren), wenn Sie wissen, dass Sie den Speicher, auf den der Zeiger zeigt, nicht ändern werden. Dies gilt für jeden Zeiger – nicht nur für void-Zeiger.

Das Umwandeln in die andere Richtung (von einem konstanten Zeiger in einen nicht konstanten Zeiger) ist eine viel gefährlichere Übung. Es gibt keine Garantie dafür, dass der Speicher, auf den gezeigt wird, tatsächlich modifizierbar ist; Beispielsweise kann ein Zeichenfolgenliteral im schreibgeschützten (konstanten) Speicher gespeichert werden, und wenn Sie die Konstante mit einer Umwandlung verlieren und versuchen, die Zeichenfolge zu ändern, erhalten Sie wahrscheinlich einen Segmentierungsfehler oder etwas Ähnliches – Ihr Programm wird plötzlich anhalten und nicht unter Ihrer Kontrolle. Das ist nicht gut. Ändern Sie also Zeiger nicht von konstant auf nicht konstant, ohne sich ganz sicher zu sein, dass es in Ordnung ist, Ihren Compiler anzulügen. Seien Sie sich bewusst, dass Compiler nicht gerne belogen werden und sich revanchieren können, normalerweise im ungünstigsten Moment (z. B. wenn Sie Ihr Programm einem wichtigen potenziellen Kunden vor Ihrem Chef, dem Chef Ihres Chefs und dem Chef des Chefs Ihres Chefs demonstrieren ).

  • “der Chef des Chefs Ihres Chefs” – ausgezeichnet, das könnte mein neues Beispiel für undefiniertes Verhalten werden. Normalerweise verwende ich “Feuer fangen”, aber jetzt denke ich darüber nach, “zu erkennen, wie viele Leute zuschauen und arbeiten, wenn es weniger als 3 sind” oder “Arbeiten, wenn und nur wenn der Code unter dem Komponententestrahmen ausgeführt wird”.

    – Steve Jessop

    5. April 2011 um 9:03 Uhr


  • Präziser sein const void * a bedeutet, dass dieser spezifische Zeiger keine Daten ändern kann, aber Zeiger auf Daten geändert werden können. Auf der anderen Seite void * const a bedeutet, dass der Zeiger unveränderlich ist, aber Daten geändert werden können. void * bedeutet, dass der veränderliche Zeiger auf Daten zeigen kann, die geändert werden können

    – Paraflou

    22. September 2016 um 12:42 Uhr


  • Für Neulinge, die Void-Zeiger in C wie ich nicht kennen: 1, In C wird General Purpose Pointer als Void-Zeiger bezeichnet; 2, Ihm ist kein Datentyp zugeordnet; 3, Es kann die Adresse jeder Art von Variable speichern; 4, Ein Void-Zeiger ist eine C-Konvention für eine Rohadresse

    – ZhaoGang

    7. August 2017 um 5:51 Uhr


Es ist vollkommen vernünftig, a zu werfen void * zu einem const void * und der Compiler sollte dies implizit hinter den Kulissen tun, ohne dass Sie darüber nachdenken, aber der umgekehrte Weg ist gefährlich und muss vermieden werden.

Denken Sie daran, wenn eine Funktion a übernimmt const Zeiger, dann können Sie entweder a const oder ein Nicht-const Wert. Sagen Sie, Sie nehmen a const Zeiger sind nur Sie, die erklären, dass der Speicher durch Ihre Funktion nicht geändert wird.

Ein Beispiel: (beachten Sie, dass die markierten Zeilen ACHTUNG sollte einen Compiler-Fehler auslösen)

const void *p_const;
void *p_buffer;

// const pointers are allowed to hold static memory
p_const = "Foo"; // allowed
p_buffer = "Foo"; // DANGER!!!

// casting to const is implicit
p_const = malloc(LEN); // allowed - implicit cast
p_buffer = malloc(LEN); // allowed

// casting to const implicit again
write(STDOUT, p_const, LEN); // allowed
write(STDOUT, p_buffer, LEN); // also allowed - implicit cast

// const memory cannot be used where mutable memory is expected
read(0, p_buffer, LEN); // allowed
read(0, p_const, LEN); // DANGER!!

// To make the above more obivous, we'll skip the intermediate variable
// and place instead what it holds
read(0, malloc(LEN), LEN); // allowed - useless but at least no crashes
read(0, "foo", 4); // DANGER!!!

Als allgemeine Regel gilt: Wenn eine von Ihnen geschriebene Funktion einen Zeiger auf einen Wert enthält, den Sie nicht ändern werden, sollte die Funktionssignatur a verwenden const Zeiger. Verwendung eines nicht deklarierten Zeigers const bedeutet, dass der Speicher, auf den Sie zeigen, geändert werden darf.

Ein anderes Beispiel:

void do_something(const void* ptr, int length);

// Since the signature is a const pointer, I know I can call it like this:
do_something("foo",4);

Umgekehrt ruft die Funktion nach einem nicht konstanten Zeiger auf, dann muss ich das zulassen:

void do_something(void* ptr, int length);

// This tells me that the function may overwrite my value.
// The safe solution therefore looks more like this:

char *myptr = char[4];
memcpy(myptr,"foo",4);    
do_something(myptr,4);

Ebenso, wenn Sie sich jemals in einer Situation befinden, in der Sie a wirken müssen const Zeiger auf ein Nicht-const Erstens sollten Sie den Wert, auf den gezeigt wird, in einen veränderlichen Teil des Speichers duplizieren und Ihr Duplikat an die Funktion und nicht an das Original übergeben. Wenn das nach Kopfschmerzen klingt, dann deshalb, weil es so ist. Wenn Sie sich in dieser Situation befinden, dann haben Sie wahrscheinlich etwas falsch gemacht.

Wenn die Variable konzeptionell einen “Wert” enthält, dann ist es wahrscheinlich a const Zeiger. Wenn es stattdessen einen “Puffer” enthält, dann ist es ein Nicht-const Zeiger.

Zeiger in Ihren Funktionssignaturen sollten stets deklariert werden const es sei denn, Sie beabsichtigen, in diesen Speicher zu schreiben. Das Befolgen dieser Regel hilft Ihnen, katastrophale Probleme in der Logik Ihres Programms zu vermeiden.

Ich verstand diese einfache Regel nicht, bis ich 6 Jahre lang programmiert hatte.

1384480cookie-checkC Frage: (const void *) vs (void *)

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy