2012-06-06 7 views
14

Esiste un modo che posso aggiungere const parola chiave ad un array passato come parametro alla funzione:Aggiunta di parola chiave const ad un array passato come parametro di funzionare

void foo(char arr_arg[]) 

Se pongo const prima char (void foo(const char arr_arg[])) o dopo char (void foo(char const arr_arg[])), ciò significherebbe che è char che è costante, non lo arr_arg.

Ho appena read che sotto il cofano una matrice inviata come parametro per funzionare è rappresentata da un puntatore, quindi void foo(char arr_arg[]) è lo stesso di void foo(char* ptr_arg). Tenendolo conto, posso riscrivere la funzione come void foo(char * const ptr_arg) perché sia ​​esattamente ciò che voglio ottenere.

Ma io voglio sapere se c'è un modo per aggiungere const parola chiave in questa dichiarazione void foo(char arr_arg[]) per essere lo stesso di void foo(char * const ptr_arg) (e nonvoid foo(char const * ptr_arg) o void foo(const char * ptr_arg))?

Voglio solo capire se c'è una sintassi per rendere costante arr_arg con la notazione di matrice [].

+4

v'è alcuna ragione specifica non si vuole fare nulla 'foo (char * const ptr_arg)'? È esattamente la stessa sintassi ovunque. Puoi ancora fare ptr_arg [0] come se fosse stato dichiarato come array. –

+0

@Hans Voglio solo capire se è sintatticamente possibile farlo con la notazione array '[]'. Nessun motivo specifico. Voglio solo chiarire se è possibile o meno (solo per sapere in futuro e non perdere tempo a contemplare se è possibile o meno ancora e ancora). – ovgolovin

+0

Non penso che sia necessario dichiarare il puntatore stesso come const in quanto verrà comunque passato per valore. Solo se si desidera proteggere esplicitamente dall'assegnazione (la copia del puntatore sullo stack) all'interno della definizione delle funzioni. –

risposta

16

In C devi mettere consttra la [], per quanto strano che possa sembrare ad una persona impreparata

void foo(char arr_arg[const]); 

Questa è "nuovo" C99-specific syntax. In C89/90 o C++ non c'è modo di farlo con la sintassi "array", quindi è necessario passare alla sintassi "pointer" equivalente, come suggerito nella risposta di David.

+0

Grazie! Accetterò la risposta tra qualche minuto (quando SO me lo consentirà). Potresti scrivere alcune parole su cosa sono C99, C89/90 (per coloro che leggeranno questa risposta, per una parte di loro non cercare Google per chiarire cosa sono)? – ovgolovin

+0

@ovgolovin aggiunto in C99 in 6.7.5.3p7 – ouah

+1

@ovgolovin: si noti che l'argomento non è ancora un array, ma un * puntatore * e quel puntatore viene copiato, il che significa che il puntatore (e la matrice) originale non può essere modificato all'interno della funzione. Se stai parlando di array reali (piuttosto che di memoria allocata dinamicamente), allora l'array è immutabile (il contenuto può essere modificato, ma l'array come contenitore non può) quindi ha poco senso contrassegnarlo come 'const' –

8

La prima cosa è che nella tua firma particolare, l'argomento viene trasformato dal compilatore in un puntatore, in modo da quello che hai è:

void foo(char * arg); 

Ora, ci sono due entità che possono essere fatte const in quella firma: il puntatore e il tipo puntato. Per rendere il tipo di punta può essere fatta const in due modi ancora equivalenti diversi [*]:

void foo(const char * arg); 
void foo(char const * arg); 

Il puntatore potrebbe essere fatto const con la sintassi:

void foo(char * const arg); 

Ma si noti che in una firma di funzione , nello stesso modo in cui char arg[] viene trasformato in un puntatore char *arg, il qualificatore di primo livello viene scartato. Quindi dal punto di vista della dichiarazione, questi due sono equivalenti:

void foo(char * const arg); 
void foo(char *  arg); 

Nella definizione, il const livello superiore può essere utilizzato per indicare al compilatore che il puntatore argomento (in valore) non deve essere modificata entro la funzione, e rileverà se si tenta di ripristinare il puntatore in una posizione diversa. Ma, se solo il puntatore è const, il compilatore ti permetterà di modificare la memoria puntata. Se non vuoi che la funzione cambi il contenuto dell'array, allora dovresti optare per una delle prime due firme.

[*] Ho tendono a preferire il formato char const *, in quanto fornisce un modo coerente di lettura tipi: da destra a sinistra si legge: un puntatore non-const ad un const char. Inoltre è più semplice ragionare sui tipi typedef (eseguendo la sostituzione diretta nell'espressione). Dato typedef char* char_p;, const char_p e char_p const sono entrambi equivalenti a char * const e diversi da const char *. Usando costantemente const sulla destra, puoi sostituire ciecamente il typedef e leggere il tipo senza doverlo ragionare.

2

Sì, in C è possibile grazie C99:

void foo(char ptr_arg[const]); 

è sintassi valida ed equivalente a

void foo(char *const ptr_arg); 

Più in generale il [] può contenere qualsiasi qualificazione tipo, static e un'espressione intera. Ma

Il tipo qualificatori opzionali e la parola static deve comparire solo in una dichiarazione di un parametro funzione con un tipo di matrice, e quindi solo nel più esterno tipo array derivazione.

che è per la dimensione che è equivalente alla dichiarazione del puntatore.

+0

@MooingDuck , Non ho mai detto che sia per il C++, per ora enfatizzo su C. E l'OP sostiene ancora che è interessato anche a C, quindi questa risposta non fa male. –

+0

Ci scusiamo per l'inesplosione. Ho solo pensato che fosse lo stesso in C e C++. Ma poi quando mi è stato chiesto, ho lasciato solo C++ (quale compilatore sto usando ora). Ma in realtà è molto interessante conoscere anche C. Ora so che era impossibile ed è diventato possibile solo con la venuta di C99. – ovgolovin

0

Per C++, la risposta di Mooing Duck utilizzando il modello è la più semplice.

Se si dispone di codice C che chiama un'interfaccia C implementato in C++, si è bloccato con la conversione l'argomento in una discussione puntatore invece, e di mettere tale const

Se si sceglie di usare Boost's array invece di utilizzare C array direttamente, allora si sarebbe in grado di fare ciò const, anche se sarebbe anche una funzione template:

template <unsigned N> 
void foo (Boost::array<char, N> const & arg) {} 

il vantaggio di Boost::array è che dà la possibilità di fare una ripartizione peso di una matrice off lo stack, ma essere in grado di riempire y utilizzare algoritmi STL che dipendono dai tratti nel contenitore.

+0

Attento con quel secondo, poiché è diverso da quello richiesto e tutte le altre risposte sulla pagina. I dati a cui punta la matrice sono locali e _also_ const. –

+0

@MooingDuck: ho modificato la risposta per sottolineare il vantaggio dell'utilizzo di Boost :: array su un array in stile C in C++ e +1 sul post. – jxh

2

Ci sono diversi modi in C++, ma nessuno è piuttosto quello che sembra essere in attesa.

//typedef has a very clear intent 
typedef char* array; 
void f0(const array a) {} 

//switch to pointers to sidestep the problem 
void f1(char* const a) {} 

//references are inherently const 
//can't take pointers, but guarantees the size, sometimes nice 
//this version obviously doesn't work in C 
template<int n> 
void f2(char (&a)[n]) {} 

http://ideone.com/4LvYT

+0

Non è 'void f0 (const array a)' uguale a 'void f0 (const char * a)' (che rende costante 'char', non' a')? – ovgolovin

+0

no, 'array' è un tipo completo e' const array' crea una variabile 'const' di tipo' array'. È un trucco molto comune quando si passano i puntatori di funzione, poiché altrimenti la sintassi è poco pratica. –

Problemi correlati