'const int' vs. 'int const' come parametri di funzione in C ++ e C


116

Tener conto di:

int testfunc1 (const int a)
{
  return a;
}

int testfunc2 (int const a)
{
  return a;
}

Queste due funzioni sono uguali in ogni aspetto o c'è una differenza?

Mi interessa una risposta per il linguaggio C, ma se c'è qualcosa di interessante nel linguaggio C ++, vorrei saperlo anch'io.


C'è una parola chiave const in C ora? Non c'era, ma non ho molta familiarità con lo standard C 99.
Onorio Catenacci

8
Non devi esserlo. C90 è sufficiente. Tuttavia non era nell'originale K&R C.
Mark Baker

3
È una parola chiave in C89 e ANSI. Non so se fosse una parola chiave ai tempi di Kerningham e Richie.
Nils Pipenbrinck

7
Questo sito traduce "C senza senso" in inglese cdecl.org
Motti

5
Direi "C senza senso in inglese senza senso", ma comunque carino :)
Kos

Risposte:


175

const Te T constsono identici. Con i tipi di puntatore diventa più complicato:

  1. const char* è un puntatore a una costante char
  2. char const* è un puntatore a una costante char
  3. char* const è un puntatore costante a (mutabile) char

In altre parole, (1) e (2) sono identici. L'unico modo per creare il puntatore (piuttosto che le punte) constè usare un suffisso- const.

Questo è il motivo per cui molte persone preferiscono mettere sempre constsul lato destro del tipo (stile "East const"): rende coerente e facile da ricordare la sua posizione rispetto al tipo (sembra anche aneddoticamente rendere più facile insegnare ai principianti ).


2
C ha const, dato: static const char foo [] = "foo"; faresti meglio a non alterare foo.
James Antill

4
K&R C non aveva const; C90 (e C99) sì. È un po 'limitato rispetto al C ++, ma è utile.
Mark Baker

questo vale anche per le referenze?
Ken,

1
@Ken Sì, è lo stesso.
Konrad Rudolph,

1
@ étale-cohomology Buon punto, aggiunto. Sarebbe dovuto essere lì da sempre.
Konrad Rudolph

339

Il trucco è leggere la dichiarazione al contrario (da destra a sinistra):

const int a = 1; // read as "a is an integer which is constant"
int const a = 1; // read as "a is a constant integer"

Entrambi sono la stessa cosa. Perciò:

a = 2; // Can't do because a is constant

Il trucco della lettura all'indietro è particolarmente utile quando hai a che fare con dichiarazioni più complesse come:

const char *s;      // read as "s is a pointer to a char that is constant"
char c;
char *const t = &c; // read as "t is a constant pointer to a char"

*s = 'A'; // Can't do because the char is constant
s++;      // Can do because the pointer isn't constant
*t = 'A'; // Can do because the char isn't constant
t++;      // Can't do because the pointer is constant

5
che dire di "char const * u"? Si legge "Un puntatore a un carattere costante" o "un puntatore che è costante a un carattere"? Sembra ambiguo. Lo standard dice il primo, ma per scoprirlo bisogna tenere conto delle regole di precedenza e di associatività.
Panayiotis Karabassis

5
@PanayiotisKarabassis Tutti dovrebbero essere trattati come una catena di aggettivi, senza scambiare alcun posto. char const *, letto da sinistra a destra è: "pointer, const, char". È un puntatore a const char. Quando dici "un puntatore che è costante", l'aggettivo "costante" è sul puntatore. Quindi, in quel caso, la tua lista di aggettivi avrebbe dovuto essere: "const, pointer, char". Ma hai ragione, c'è ambiguità in questo trucco. È davvero un "trucco", più che una "regola" definitiva.
Ates Goral

5
Quando dichiari una combinazione selvaggia di array, funzione, puntatore e puntatore a funzione, la lettura all'indietro non funziona più (purtroppo). Tuttavia, puoi leggere queste dichiarazioni disordinate in uno schema a spirale . Altri erano così frustrati da loro che inventarono Go.
Martin JH

@ Martin JH: Non potrebbero essere suddivisi per mezzo di typedef? E / o utilizzare riferimenti per eliminare le indirettezze?
Peter Mortensen

14

Non c'è differenza. Entrambi dichiarano "a" un numero intero che non può essere modificato.

Il punto in cui iniziano ad apparire le differenze è quando usi i puntatori.

Entrambi:

const int *a
int const *a

dichiarare "a" come puntatore a un numero intero che non cambia. "a" può essere assegnato, ma "* a" no.

int * const a

dichiara "a" come puntatore costante a un numero intero. "* a" può essere assegnato, ma "a" no.

const int * const a

dichiara "a" come puntatore costante a un numero intero costante. Non è possibile assegnare né "a" né "* a".

static int one = 1;

int testfunc3 (const int *a)
{
  *a = 1; /* Error */
  a = &one;
  return *a;
}

int testfunc4 (int * const a)
{
  *a = 1;
  a = &one; /* Error */
  return *a;
}

int testfunc5 (const int * const a)
{
  *a = 1;   /* Error */
  a = &one; /* Error */
  return *a;
}

L'ultimo esempio è la spiegazione più semplice, fantastico!
exru

7

Prakash ha ragione sul fatto che le dichiarazioni sono le stesse, anche se potrebbe essere necessaria una spiegazione un po 'più del caso del puntatore.

"const int * p" è un puntatore a un int che non consente la modifica di int tramite quel puntatore. "int * const p" è un puntatore a un int che non può essere modificato per puntare a un altro int.

Vedi https://isocpp.org/wiki/faq/const-correctness#const-ptr-vs-ptr-const .


L'ancora ("faq-18.5.) È rotta. A quale dovrebbe riferirsi (ce ne sono diversi con" const "e" * ")?
Peter Mortensen

@ PeterMortensen: Sì, link rot. Grazie. Ho aggiornato il collegamento.
Fred Larson

5

const intè identico a int const, come è vero con tutti i tipi scalari in C. In generale, dichiarare un parametro di funzione scalare come constnon è necessario, poiché la semantica di chiamata per valore di C significa che qualsiasi modifica alla variabile è locale alla sua funzione che lo racchiude.


4

Questa non è una risposta diretta ma un suggerimento correlato. Per mantenere le cose dritte, uso sempre la convezione "messo constfuori", dove per "esterno" intendo l'estrema sinistra o l'estrema destra. In questo modo non c'è confusione: la const si applica alla cosa più vicina (il tipo o il *). Per esempio,



int * const foo = ...; // Pointer cannot change, pointed to value can change
const int * bar = ...; // Pointer can change, pointed to value cannot change
int * baz = ...; // Pointer can change, pointed to value can change
const int * const qux = ...; // Pointer cannot change, pointed to value cannot change

6
Forse è meglio usare la regola "const rende const quello che ne resta". Ad esempio "int * const foo" rende il puntatore "const", perché il puntatore viene lasciato ad esso. Tuttavia, dovresti scrivere la seconda riga "int const * bar", rende int const, perché è lasciato a esso. "int const * const * qux", rende entrambi, int e puntatore, const, perché uno di essi è lasciato una volta.
Mecki

4

Sono gli stessi, ma in C ++ c'è una buona ragione per usare sempre const a destra. Sarai coerente ovunque perché le funzioni membro const devono essere dichiarate in questo modo:

int getInt() const;

Cambia il thispuntatore nella funzione da Foo * consta Foo const * const. Vedere qui.


3
Questo è un tipo di const completamente diverso.
Justin Meiners

1
Perché è completamente diverso? Abbastanza diverso da guadagnare un voto negativo.
Nick Westgate

1
Sì, la domanda riguarda la differenza tra "const int" e "int const", la tua risposta non ha nulla a che fare con questo.
Justin Meiners

1
Ho detto che sono la stessa cosa. Eppure le risposte accettate e quelle più votate forniscono anche informazioni aggiuntive sui tipi di puntatore. Hai svalutato anche quelli?
Nick Westgate

3

Sì, sono gli stessi per solo int

e diverso per int*


5
(const int *) e (int const *) sono uguali, sono solo diversi da (int * const).
James Antill

3

Penso che in questo caso siano gli stessi, ma ecco un esempio in cui l'ordine è importante:

const int* cantChangeTheData;
int* const cantChangeTheAddress;

2
In effetti, ma int const * è uguale al primo, quindi l'ordine di int e const non ha importanza, è solo l'ordine di * e const che lo fa.
Mark Baker
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.