Domanda

Il seguente frammento di codice (correttamente) dà un avvertimento in C e un errore in C++ (gcc & g++, rispettivamente, testato con le versioni 3.4.5 e 4.2.1;MSVC non sembrano cura):

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

Sono in grado di capire e accettare questo.
Il C++ soluzione a questo problema è quello di cambiare la b per essere un const char * const *, che non permetteva la riassegnazione dei puntatori e impedisce di eludere const-correttezza (C++ FAQ).

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

Tuttavia, in puro C, la versione corretta (uso di const char * const *) dà ancora un avvertimento, e non capisco perché.C'è un modo per ottenere tutto questo senza l'utilizzo di un cast?

Per chiarire:
1) Perché questo genera un messaggio di avviso in C?Dovrebbe essere interamente const-safe, e il compilatore C++ sembra di riconoscerlo come tale.
2) Qual è il modo giusto per andare su di accettare questo char** come parametro dicendo (e di avere il compilatore applicare) che io non modificare i caratteri che punti?Per esempio, se volessi scrivere una funzione:

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

E ho voluto richiamare su un char**, quale sarebbe il tipo corretto per il parametro?

Edit:Grazie a tutti coloro che hanno risposto, in particolare per chi ha affrontato la questione e/o di seguito le mie risposte.

Ho accettato la risposta che quello che voglio fare non può essere fatto senza un cast, indipendentemente dal fatto che o non dovrebbe essere possibile.

È stato utile?

Soluzione

Ho avuto lo stesso problema un paio di anni fa e non mi aveva infastidito a non finire.

Le regole in C sono più semplicemente (es.non elenco le eccezioni, come la conversione di char** per const char*const*).Successivamente, è non solo consentito.Con il C++ standard, hanno incluso più regole per consentire casi come questo.

Alla fine, è solo un problema in C standard.Spero che la prossima standard (o relazione tecnica) in grado di affrontare questo.

Altri suggerimenti

Per essere considerato compatibile, la fonte puntatore deve essere const immediatamente anteriore livello di riferimento indiretto.Quindi, questo vi darà l'avviso di GCC:

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

Ma non è per questo:

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

In alternativa, è possibile eseguire il cast:

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

Si avrebbe bisogno lo stesso cast di richiamare la funzione f() come hai detto.Per quanto ne so, non c'è modo di fare una conversione implicita in questo caso (tranne che in C++).

> Comunque, in C puro, questo ancora dà un avvertimento, e non capisco perché

Hai già individuato il problema, questo codice non è const-corretto."Const corretto" significa che, fatta eccezione per const_cast e C-stile lancia la rimozione const, non si può mai modificare un oggetto const attraverso quelle const puntatori o riferimenti.

Il valore di const-correttezza -- const c'è, in gran parte, per rilevare programmatore errori.Se si dichiara qualcosa come const, stai affermando che non si pensa che dovrebbe essere modificata, o almeno, coloro che hanno accesso alla const solo per la versione non dovrebbe essere in grado di modificarlo.Prendere in considerazione:

void foo(const int*);

Come dichiarato, pippo non ha autorizzazione per modificare il numero intero a cui punta il suo argomento.

Se non siete sicuri perché il codice che hai postato non è const-corretto, si consideri il seguente codice, solo leggermente diverso da HappyDude codice:

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;

Non const tipi può solo convertire i tipi di const in modi particolari per evitare qualsiasi elusione del 'const' un tipo di dati senza un cast esplicito.

Oggetti inizialmente dichiarato const sono particolarmente speciale, il compilatore può supporre che non cambiano mai.Tuttavia, se la " b " può essere assegnato il valore di 'a' senza un cast, allora si potrebbe toccare involontariamente tentativo di modificare una variabile const.Non si tratta solo di rompere il controllo ha chiesto al compilatore di fare, di non consentire la modifica delle variabili di valore-si consentirebbe anche rompere le ottimizzazioni del compilatore!

Su alcuni compilatori, questo stampa '42', su alcune '43', e gli altri, il programma andrà in crash.

Modifica-aggiungi:

HappyDude:Il tuo commento è a posto.Il C lingua, o il compilatore C che si sta utilizzando, tratta const char * const * in modo fondamentalmente diverso rispetto al linguaggio C++ tratta.Forse pensare a tacere l'avviso del compilatore per questa riga di codice sorgente solo.

Edit-delete: rimosso l'errore di battitura

Questo è fastidioso, ma se hai voglia di aggiungere un altro livello di reindirizzamento, spesso è possibile fare le seguenti a spingere verso il basso il puntatore a puntatore:

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

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

Esso ha un significato leggermente diverso, ma di solito è realizzabile, e non fa uso di un cast.

Io non sono in grado di ottenere un messaggio di errore quando implicitamente il cast char** const char * const *, almeno in MSVC 14 (VS2k5) e g++ 3.3.3.GCC 3.3.3 un avvertimento, che non sono esattamente sicuro di se è corretto nel fare.

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; 
}

Uscita con come compilare codice C:cl /TC /W4 /Wp64 test.c

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

Uscita con come compilare il codice C++:cl /TP /W4 /Wp64 test.c

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

Uscita con 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

Uscita con g++:g++ -Wall test.C

nessun output

Sono abbastanza sicuro che la parola chiave const non implica che i dati non possono essere modificati/è costante, solo che i dati saranno trattati come di sola lettura.Considerate questo:

const volatile int *const serial_port = SERIAL_PORT;

che è un codice valido.Come si può volatili e const co-esistere?Semplice.volatile indica al compilatore di leggere sempre la memoria con i dati e const indica al compilatore di creare un messaggio di errore quando si tenta di scrivere la memoria utilizzando il serial_port puntatore.

Non const aiutare il compilatore lo strumento per ottimizzare?No.Non a tutti.Perché constness ' possono essere aggiunti e rimossi dai dati attraverso la fusione, il compilatore non riesce a capire se const dati davvero è costante (dal momento che il lancio possa essere fatto in diverse unità di traduzione).In C++, è anche la parola chiave public a complicare ulteriormente le cose.

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

Cosa succede quando viene effettuato un tentativo di scrittura in memoria che in realtà è in sola lettura (ROM, per esempio), probabilmente non è definito nello standard a tutti.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top