Perché l’asterisco prima del nome della variabile, piuttosto che dopo il tipo?

Perché la maggior parte dei programmatori C nomina variabili come questa:

int *myVariable; 

piuttosto che così:

 int* myVariable; 

Entrambi sono validi. Mi sembra che l’asterisco sia una parte del tipo, non una parte del nome della variabile. Qualcuno può spiegare questa logica?

Sono ESATTAMENTE equivalenti. Tuttavia, in

 int *myVariable, myVariable2; 

Sembra ovvio che myVariable abbia tipo int * , mentre myVariable2 ha tipo int . In

 int* myVariable, myVariable2; 

può sembrare ovvio che entrambi siano di tipo int * , ma non è corretto in quanto myVariable2 ha tipo int .

Pertanto, il primo stile di programmazione è più intuitivo.

Se lo guardi in un altro modo, *myVariable è di tipo int , il che ha un senso.

Perché * si lega più strettamente alla variabile che al tipo:

 int* varA, varB; // This is misleading 

Tuttavia, anche le migliori dichiarazioni su riga singola mi sembrano contro-intuitive, perché il * è parte del tipo. Mi piace farlo invece:

 int* varA; int varB; 

Come al solito, meno il tuo codice è compatto, più è leggibile. 😉

Qualcosa che nessuno ha menzionato finora è che questo asterisco è in realtà “l’ operatore della dereferenza ” in C.

 *a = 10; 

La riga sopra non significa che voglio assegnare 10 a a , vuol dire che voglio assegnare 10 a qualsiasi posizione di memoria a punta. E non ho mai visto nessuno scrivere

 * a = 10; 

hai? Quindi l’ operatore di dereferenziazione è praticamente sempre scritto senza spazio. Questo è probabilmente per distinguerlo da una moltiplicazione suddivisa su più righe:

 x = a * b * c * d * e * f * g; 

Qui *e sarebbe fuorviante, no?

Ok, ora che cosa significa in realtà la seguente riga:

 int *a; 

La maggior parte delle persone direbbe:

Significa che a è un puntatore a un valore int .

Questo è tecnicamente corretto, alla maggior parte delle persone piace vederlo / leggerlo in quel modo e questo è il modo in cui i moderni standard C lo definiscono (si noti che il linguaggio C stesso precede tutti gli standard ANSI e ISO). Ma non è l’unico modo per vederlo. Puoi anche leggere questa riga come segue:

Il valore di riferimento di a è di tipo int .

Pertanto, l’asterisco in questa dichiarazione può anche essere visto come un operatore di dereferenziazione, che spiega anche il suo posizionamento. E che a è che un puntatore non è realmente dichiarato, è implicito dal fatto che l’unica cosa che puoi effettivamente dereferenziare è un puntatore.

Lo standard C definisce solo due significati per l’operatore * :

  • operatore indiretto
  • operatore di moltiplicazione

E l’indirezione è solo un significato, non c’è un significato in più per dichiarare un puntatore, c’è solo l’indirezione, che è ciò che fa l’operazione di dereferenziazione, esegue un accesso indiretto, quindi anche all’interno di un’istruzione come int *a; questo è un accesso indiretto ( * significa accesso indiretto) e quindi la seconda affermazione sopra è molto più vicina allo standard di quella precedente.

Vado qui su un arto e dico che c’è una risposta diretta a questa domanda , sia per le dichiarazioni variabili che per i parametri e i tipi di ritorno, che è che l’asterisco dovrebbe andare vicino al nome: int *myVariable; . Per apprezzare il motivo, guarda come si dichiarano altri tipi di simbolo in C:

int my_function(int arg); per una funzione;

float my_array[3] per un array.

Lo schema generale, indicato come dichiarazione, segue l’uso , è che il tipo di un simbolo è suddiviso nella parte prima del nome e le parti attorno al nome, e queste parti attorno al nome imitano la syntax che si utilizzerà per ottenere un valore del tipo a sinistra:

int a_return_value = my_function(729);

float an_element = my_array[2];

e: int copy_of_value = *myVariable; .

C ++ lancia una chiave nei lavori con i riferimenti, perché la syntax nel punto in cui si usano i riferimenti è identica a quella dei tipi di valore, quindi si potrebbe sostenere che C ++ adotta un approccio diverso a C. D’altra parte, C ++ conserva lo stesso comportamento di C nel caso dei puntatori, quindi i riferimenti sono davvero fuori dal comune.

È solo una questione di preferenza.

Quando leggi il codice, distinguere tra variabili e puntatori è più semplice nel secondo caso, ma può portare a confusione quando stai mettendo sia le variabili che i puntatori di un tipo comune in una singola riga (che a sua volta è spesso scoraggiata dalle linee guida del progetto, perché diminuisce la leggibilità).

Preferisco dichiarare i puntatori con il loro segno corrispondente accanto al nome del tipo, ad es

 int* pMyPointer; 

Un grande guru una volta disse: “Leggi come si usa il compilatore, devi”.

http://www.drdobbs.com/conversationsa-midsummer-nights-madness/184403835

Concesso che questo era sul tema del posizionamento const, ma qui si applica la stessa regola.

Il compilatore lo legge come:

 int (*a); 

non come:

 (int*) a; 

Se prendi l’abitudine di posizionare la stella accanto alla variabile, renderà le tue dichiarazioni più facili da leggere. Evita anche i brutti occhi come:

 int* a[10]; 

Perché ha più senso quando hai dichiarazioni come:

 int *a, *b; 

Per dichiarare più puntatori in una riga, preferisco int* a, * b; che dichiara in modo più intuitivo “a” come puntatore a un intero e non mescola gli stili quando dichiara anche “b”. Come qualcuno ha detto, non dichiarerei comunque due tipi diversi nella stessa dichiarazione.

In K & R, posizionano l’operatore puntatore vicino al nome della variabile piuttosto che al tipo. Personalmente, ritengo che il libro sia l’ultima autorità / bibbia C. Provenendo anch’esso da uno sfondo Objective-C, seguo la convenzione del nome *.

Ho già risposto a una domanda simile in CP e, poiché nessuno lo ha detto, anche qui devo sottolineare che C è un linguaggio in formato libero , qualunque sia lo stile scelto, mentre il parser può fare una distinzione di ciascun token. Questa particolarità di C porta ad un tipo molto speciale di concorso chiamato concorso di offuscamento di C.