'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.