Frage

Der folgende Code-Schnipsel (richtig) gibt eine Warnung in C und einen Fehler in C ++ (mit gcc & g ++ bzw. getestet mit den Versionen 3.4.5 und 4.2.1; MSVC scheint nicht zu kümmern):

char **a;
const char** b = a;

Das kann ich verstehen und akzeptieren.
Die C ++ Lösung für dieses Problem ist, b zu ändern eine const char * const * zu sein, die Neuzuordnung der Zeiger nicht zulässt und verhindert, dass Sie Umgehen const-Korrektheit ( C ++ FAQ ).

char **a;
const char* const* b = a;

Doch in reinem C, die korrigierte Version (const char * const * verwendet) gibt immer noch eine Warnung, und ich verstehe nicht, warum. Gibt es eine Möglichkeit, dies zu umgehen, ohne eine Besetzung mit?

Zur Klarstellung:
1) Warum generiert dies eine Warnung in C? Es sollte ganz konst sicher sein, und die C ++ Compiler scheint es, als solche zu erkennen.
2) Was ist der richtige Weg, um über die Annahme dieser Zeichen zu gehen ** als Parameter während sagen (und mit der Compiler erzwingen), dass ich nicht die Zeichen werden modifiziert verweist er auf? Zum Beispiel, wenn ich will, eine Funktion schreiben:

void f(const char* const* in) {
  // Only reads the data from in, does not write to it
}

Und ich wollte es auf einem char aufzurufen **, was der richtige Typ für den Parameter sein würde?

Edit: Vielen Dank an diejenigen, die geantwortet haben, vor allem diejenigen, die die Frage gerichtet und / oder auf meiner Antworten weiterverfolgt.

Ich habe die Antwort akzeptiert, was ich kann tun will nicht ohne Guss, unabhängig davon erfolgen, ob oder nicht soll es möglich sein.

War es hilfreich?

Lösung

Ich hatte das gleiche Problem vor ein paar Jahren und es ärgert mich ohne Ende.

Die Regeln in C sind einfacher ausgedrückt (das heißt, sie führen keine Ausnahmen wie char** Umwandlung zu const char*const*). Consequenlty, es ist einfach nicht erlaubt. Mit dem C ++ Standard, enthalten sie mehr Regeln Fälle wie diesen zu ermöglichen.

Am Ende, es ist nur ein Problem in dem Standard-C. Ich hoffe, dass der nächste Standard (oder technischer Bericht) wird diese Adresse.

Andere Tipps

vereinbar angesehen, soll der Quellenzeiger const in der unmittelbar vorderen indirection Ebene. Also, dies wird Ihnen die Warnung in GCC:

char **a;
const char* const* b = a;

Das wird aber nicht:

const char **a;
const char* const* b = a;

Alternativ können Sie es Stimmen:

char **a;
const char* const* b = (const char **)a;

Sie müssten die gleiche Besetzung der Funktion f () aufzurufen, wie Sie bereits erwähnt. Soweit ich weiß, gibt es keine Möglichkeit, eine implizite Konvertierung in diesem Fall zu machen (außer in C ++).

> jedoch in reinem C, das gibt noch eine Warnung, und ich verstehe nicht, warum

Sie haben bereits das Problem erkannt - dieser Code ist nicht const-korrekt. „Const richtig“ bedeutet, dass, mit Ausnahme von const_cast und C-Casts const entfernen, man kann nie ein konstantes Objekt durch diese const Zeiger oder Verweise ändern.

Der Wert von const-Korrektheit - const ist es, zu einem großen Teil, Programmierer, Fehler zu erkennen. Wenn Sie etwas als const deklarieren, Sie besagt, dass Sie nicht denken, es sollte geändert werden - oder zumindest diejenigen mit Zugriff auf die const-Version sollte nur nicht zu modifizieren sie in der Lage sein. Bedenken Sie:

void foo(const int*);

Wie erklärt, foo nicht über Erlaubnis die ganze Zahl zu ändern, auf die von ihr Argument.

Wenn Sie nicht sicher sind, warum der Code, den Sie ist nicht gebucht const korrigieren, sollten Sie den folgenden Code, nur geringfügig von HappyDude Code:

char *y;

char **a = &y; // a points to y
const char **b = a; // now b also points to y

// const protection has been violated, because:

const char x = 42; // x must never be modified
*b = &x; // the type of *b is const char *, so set it 
         //     with &x which is const char* ..
         //     ..  so y is set to &x... oops;
*y = 43; // y == &x... so attempting to modify const 
         //     variable.  oops!  undefined behavior!
cout << x << endl;

Nicht konstante Typen kann nur auf const Arten in besonderer Weise konvertiert auf einem Datentyp ohne eine explizite Umwandlung eine Umgehung von ‚const‘ zu verhindern.

Objekte zunächst const deklariert sind etwas ganz Besonderes - der Compiler davon ausgehen, können sie sich nie ändern. wenn ‚b‘ zugeordnet werden kann, jedoch den Wert von ‚a‘ ohne gegossen, dann könnte man versehentlich versuchen, ein const-Variable zu ändern. Dies würde nicht nur bricht die Prüfung Sie den Compiler gefragt zu machen, die Sie nicht zulassen aus, dass Variablen Wert zu ändern - es Ihnen erlauben würde, auch die Compiler-Optimierungen brechen

!

Bei einigen Compiler wird diese ‚42‘ drucken, auf einige ‚43‘, und andere, wird das Programm zum Absturz bringen.

Edit-add:

HappyDude: Dein Kommentar ist vor Ort auf. Entweder ist das C Langauge oder die C-Compiler Sie verwenden, behandelt const char * const * grundlegend anders als die Sprache C ++ es behandelt. Vielleicht sollten Sie die Compiler für diese Quellenleitung nur Warnung zum Schweigen zu bringen.

Edit-löschen: entfernt Typo

Das ist ärgerlich, aber wenn Sie bereit sind, eine weitere Ebene der Umleitung hinzufügen möchten, können Sie die folgenden Funktionen nach unten drücken, in den Zeiger-to-Zeiger oft:

char c = 'c';
char *p = &c;
char **a = &p;

const char *bi = *a;
const char * const * b = &bi;

Es hat eine etwas andere Bedeutung, aber es ist in der Regel praktikabel, und es ist kein Guss verwenden.

Ich bin nicht in der Lage, einen Fehler zu erhalten, wenn implizit char Casting ** const char * const *, zumindest auf MSVC 14 (VS2k5) und g ++ 3.3.3. 3.3.3 GCC gibt eine Warnung aus, die ich bin mir nicht ganz sicher, ob es richtig ist, zu tun.

test.c:

#include <stdlib.h> 
#include <stdio.h>
void foo(const char * const * bar)
{
    printf("bar %s null\n", bar ? "is not" : "is");
}

int main(int argc, char **argv) 
{
    char **x = NULL; 
    const char* const*y = x;
    foo(x);
    foo(y);
    return 0; 
}

Ausgabe mit der Kompilierung als C-Code: cl / TC / W4 / Wp64 test.c

test.c(8) : warning C4100: 'argv' : unreferenced formal parameter
test.c(8) : warning C4100: 'argc' : unreferenced formal parameter

Ausgabe mit der Kompilierung als C ++ Code: cl / TP / W4 / Wp64 test.c

test.c(8) : warning C4100: 'argv' : unreferenced formal parameter
test.c(8) : warning C4100: 'argc' : unreferenced formal parameter

Ausgabe mit gcc: gcc -Wall test.c

test2.c: In function `main':
test2.c:11: warning: initialization from incompatible pointer type
test2.c:12: warning: passing arg 1 of `foo' from incompatible pointer type

Ausgabe mit g ++: g ++ -Wall test.c

keine Ausgabe

Ich bin ziemlich sicher, dass das Schlüsselwort const kann nicht die Daten impliziert nicht geändert werden / konstant ist, nur dass die Daten als schreibgeschützt behandelt werden. Bedenken Sie:

const volatile int *const serial_port = SERIAL_PORT;

Das ist gültige Code. Wie kann flüchtige und const koexistieren? Einfach. volatiles teilt den Compiler, immer den Speicher gelesen werden, wenn die Daten mit und const teilt den Compiler einen Fehler zu erzeugen, wenn ein Versuch schreiben wird, den serial_port Zeiger auf den Speicher.

Hat const Optimiser Compiler helfen? Nein überhaupt nicht. Da Konstantheit zu und von Daten, die durch Gießen entfernt hinzugefügt werden kann, kann der Compiler nicht herausfinden, ob const Daten wirklich konstant ist (da die Besetzung in einer anderen Übersetzungseinheit getan werden könnte). In C ++ haben Sie auch das wandelbar Schlüsselwort Angelegenheiten erschweren weiter.

char *const p = (char *) 0xb000;
//error: p = (char *) 0xc000;
char **q = (char **)&p;
*q = (char *)0xc000; // p is now 0xc000

Was passiert, wenn versucht wird, den Speicher zu schreiben, die wirklich nur gelesen (ROM, zum Beispiel) wahrscheinlich nicht in der Norm definiert ist.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top