Posizionamento dell'asterisco nelle dichiarazioni del puntatore


92

Recentemente ho deciso che devo solo imparare finalmente C / C ++, e c'è una cosa che non capisco veramente sui puntatori o più precisamente, la loro definizione.

Che ne dici di questi esempi:

  1. int* test;
  2. int *test;
  3. int * test;
  4. int* test,test2;
  5. int *test,test2;
  6. int * test,test2;

Ora, per quanto ne so, i primi tre casi stanno facendo tutti lo stesso: Test non è un int, ma un puntatore a uno.

La seconda serie di esempi è un po 'più complicata. Nel caso 4, sia test che test2 saranno puntatori a un int, mentre nel caso 5, solo test è un puntatore, mentre test2 è un int "reale". E il caso 6? Come il caso 5?


10
In C / C ++ gli spazi bianchi non cambiano significato.
Sulthan

19
7. int*test;?
Jin Kwon

3
+1 perché avevo pensato di chiedere solo 1 - 3. Leggere questa domanda mi ha insegnato qualcosa su 4 - 6 a cui non avevo mai pensato.
vastlysuperiorman

@Sulthan Questo è vero il 99% delle volte, ma non sempre. In cima alla mia testa c'era il tipo di tipo basato su modelli nel requisito di spazio per i caratteri basato su modelli (pre C ++ 11). Nel Foo<Bar<char>>il >>doveva essere scritta > >in modo da non essere trattati come un diritto-shift.
AnorZaken

3
@AnorZaken Hai ragione, questo è un commento piuttosto vecchio. Ci sono più situazioni in cui uno spazio cambia significato, ad esempio, l' ++operatore di incremento non può essere diviso da uno spazio, gli identificatori non possono essere divisi da uno spazio (e il risultato può essere ancora legale per il compilatore ma con un comportamento di runtime non definito). Le situazioni esatte sono molto difficili da definire considerando il pasticcio di sintassi che è C / C ++.
Sulthan

Risposte:


129

4, 5 e 6 sono la stessa cosa, solo il test è un puntatore. Se vuoi due puntatori, dovresti usare:

int *test, *test2;

O ancora meglio (per chiarire tutto):

int* test;
int* test2;

3
Quindi il caso 4 è in realtà una trappola mortale, allora? C'è qualche specifica o ulteriore lettura che spiega perché int * test, test2 rende solo la prima variabile un puntatore?
Michael Stum

8
@ Michael Stum È C ++ quindi pensi davvero che ci sia una spiegazione logica?
Joe Phillips

6
Leggi K&R (The C Programming Language). Spiega tutto questo molto chiaramente.
Ferruccio

8
I casi 4, 5 e 6 sono "trappole mortali". Questa è una delle ragioni per cui molti gudes in stile C / C ++ suggeriscono solo una dichiarazione per istruzione.
Michael Burr,

14
Lo spazio vuoto è insignificante per un compilatore C (ignorando il preprocessore). Quindi, non importa quanti spazi ci sono o meno tra l'asterisco e l'ambiente circostante, ha esattamente lo stesso significato.
effimero

45

Lo spazio bianco attorno agli asterischi non ha alcun significato. Tutti e tre significano la stessa cosa:

int* test;
int *test;
int * test;

" int *var1, var2" È una sintassi malvagia che ha lo scopo di confondere le persone e dovrebbe essere evitata. Si espande a:

int *var1;
int var2;

16
Non dimenticare int*test.
Mateen Ulhaq

1
lo spazio prima o dopo l'asterisco è solo una questione di estetica. Tuttavia, lo standard di codifica di Google va con int *test( google-styleguide.googlecode.com/svn/trunk/… ). Sii coerente

@SebastianRaschka La Guida allo stile di Google C ++ consente esplicitamente il posizionamento di un asterisco. Forse è cambiato da quando l'hai letto.
Jared Beck

33

Molte linee guida di codifica consigliano di dichiarare solo una variabile per riga . Ciò evita qualsiasi confusione del tipo che avevi prima di porre questa domanda. La maggior parte dei programmatori C ++ con cui ho lavorato sembra attenersi a questo.


Un po 'a parte lo so, ma qualcosa che ho trovato utile è leggere le dichiarazioni al contrario.

int* test;   // test is a pointer to an int

Questo inizia a funzionare molto bene, specialmente quando inizi a dichiarare i puntatori const e diventa difficile sapere se è il puntatore che è const, o se è la cosa a cui punta il puntatore che è const.

int* const test; // test is a const pointer to an int

int const * test; // test is a pointer to a const int ... but many people write this as  
const int * test; // test is a pointer to an int that's const

Anche se "una variabile per riga" sembra utile, non abbiamo ancora risolto completamente la situazione in cui l'asterisco è più a sinistra o più a destra. Sono abbastanza sicuro che nel code out in the wild prevale una variante; un po 'come alcuni paesi guidano sul lato destro e gli altri guidano nella direzione sbagliata, come il Regno Unito. ;-)
shevy il

Sfortunatamente dalle mie avventure nella natura selvaggia vedo molti di entrambi gli stili. Nella mia squadra ora usiamo il formato clang con uno stile che abbiamo concordato. Questo significa almeno che tutto il codice prodotto dal nostro team ha lo stesso stile per dove vanno gli spazi.
Scott Langham il

33

Utilizzare la "Regola spirale in senso orario" per analizzare le dichiarazioni C / C ++;

Ci sono tre semplici passaggi da seguire:

  1. Partendo dall'elemento sconosciuto, muoviti in senso spirale / orario; quando si incontrano i seguenti elementi, sostituirli con le corrispondenti istruzioni in inglese:

    [X]oppure []: Array X size of ... o Array undefined size of ...

    (type1, type2): funzione che passa tipo1 e tipo2 restituisce ...

    *: puntatore / i a ...

  2. Continua a farlo in una direzione a spirale / in senso orario finché tutti i gettoni non sono stati coperti.
  3. Risolvi sempre prima qualsiasi cosa tra parentesi!

Inoltre, le dichiarazioni dovrebbero essere in dichiarazioni separate quando possibile (il che è vero la stragrande maggioranza delle volte).


4
Sembra scoraggiante e piuttosto orribile, mi dispiace dirlo.
Joe Phillips,

7
sì, ma sembra una spiegazione abbastanza buona per alcuni dei costrutti più complicati
Michael Stum

@ d03boy: Non ci sono dubbi: le dichiarazioni C / C ++ possono essere un incubo.
Michael Burr

2
La "spirale" non ha alcun senso, tanto meno il "senso orario". Preferisco chiamarla "regola destra-sinistra", poiché la sintassi non ti fa sembrare destra-basso-sinistra-alto, solo destra-sinistra.
Ruslan

L'ho imparato come regola "destra-sinistra-destra". Alla gente del C ++ spesso piace fingere che tutte le informazioni sul tipo siano a sinistra, il che porta allo int* x;stile piuttosto che allo int *x;stile tradizionale . Ovviamente, la spaziatura non ha importanza per il compilatore, ma influisce sugli umani. La negazione della sintassi effettiva porta a regole di stile che possono infastidire e confondere i lettori.
Adrian McCarthy

12

Come altri menzionati, 4, 5 e 6 sono gli stessi. Spesso le persone usano questi esempi per fare l'argomento che *appartiene alla variabile invece che al tipo. Sebbene sia una questione di stile, si discute se dovresti pensarla e scriverla in questo modo:

int* x; // "x is a pointer to int"

o in questo modo:

int *x; // "*x is an int"

FWIW Sono nel primo campo, ma il motivo per cui altri sostengono la seconda forma è che risolve (principalmente) questo particolare problema:

int* x,y; // "x is a pointer to int, y is an int"

che è potenzialmente fuorviante; invece scriveresti neanche tu

int *x,y; // it's a little clearer what is going on here

o se vuoi davvero due suggerimenti,

int *x, *y; // two pointers

Personalmente, dico di mantenerlo su una variabile per riga, quindi non importa quale stile preferisci.


6
questo è falso, come chiami int *MyFunc(void)? a *MyFuncè una funzione che restituisce un int? no. Ovviamente dovremmo scrivere int* MyFunc(void), e dire MyFuncè una funzione che restituisce a int*. Quindi per me questo è chiaro, le regole di analisi grammaticale C e C ++ sono semplicemente sbagliate per la dichiarazione delle variabili. avrebbero dovuto includere la qualificazione del puntatore come parte del tipo condiviso per l'intera sequenza di virgole.
v

1
Ma *MyFunc() è un file int. Il problema con la sintassi C sta mescolando prefisso e sintassi postfisso - se fosse usato solo suffisso, non ci sarebbe confusione.
Antti Haapala

1
Il primo campo combatte la sintassi del linguaggio, portando a costrutti confusi come int const* x;, che trovo fuorvianti quanto a * x+b * y.
Adrian McCarthy


5

In 4, 5 e 6, testè sempre un puntatore e test2non è un puntatore. Lo spazio bianco non è (quasi) mai significativo in C ++.


3

A mio parere, la risposta è ENTRAMBE, a seconda della situazione. In generale, IMO, è meglio mettere l'asterisco accanto al nome del puntatore, piuttosto che il tipo. Confronta ad esempio:

int *pointer1, *pointer2; // Fully consistent, two pointers
int* pointer1, pointer2;  // Inconsistent -- because only the first one is a pointer, the second one is an int variable
// The second case is unexpected, and thus prone to errors

Perché il secondo caso è incoerente? Perché ad esempio int x,y;dichiara due variabili dello stesso tipo ma il tipo è menzionato solo una volta nella dichiarazione. Questo crea un comportamento precedente e previsto. Ed int* pointer1, pointer2;è incoerente con questo perché si dichiara pointer1come un puntatore, ma pointer2è una variabile intera. Chiaramente incline agli errori e, quindi, dovrebbe essere evitato (mettendo l'asterisco accanto al nome del puntatore, piuttosto che il tipo).

Tuttavia , ci sono alcune eccezioni in cui potresti non essere in grado di mettere l'asterisco accanto al nome di un oggetto (e dove è importante dove lo metti) senza ottenere risultati indesiderati, ad esempio:

MyClass *volatile MyObjName

void test (const char *const p) // const value pointed to by a const pointer

Infine, in alcuni casi, potrebbe essere più chiaro mettere l'asterisco accanto al nome del tipo , ad esempio:

void* ClassName::getItemPtr () {return &item;} // Clear at first sight


2

La logica in C è che dichiari le variabili nel modo in cui le usi. Per esempio

char *a[100];

dice che *a[42]sarà un file char. E a[42]un puntatore di caratteri. E quindia è un array di puntatori di caratteri.

Questo perché gli autori del compilatore originale volevano utilizzare lo stesso parser per espressioni e dichiarazioni. (Non è una ragione molto sensata per una scelta di design della lingua)


Tuttavia la scrittura deduce char* a[100]; anche che *a[42];sarà un chare a[42];un puntatore di caratteri.
yyny

Ebbene, tutti deduciamo le stesse conclusioni, solo l'ordine varia.
Michel Billaud

Quote: "dice che * a [42] sarà un carattere. E a [42] un puntatore di carattere". Sei sicuro che non sia il contrario?
deLock

Se preferisci l'altro modo, diciamo a[42]è un charpuntatore e *a[42]è un carattere.
Michel Billaud

2

Direi che la convenzione iniziale era quella di mettere la stella sul lato del nome del puntatore (lato destro della dichiarazione

Puoi seguire le stesse regole, ma non è un grosso problema se metti le stelle sul lato del tipo. Ricorda che la coerenza è importante, quindi sempre ma la stella dalla stessa parte indipendentemente da quale lato hai scelto.


Bene, il parser sembra consentire entrambe le varianti, ma se Dennis e Linus dicono che dovrebbe essere sul lato destro, è abbastanza convincente. Tuttavia, ci manca un po 'di logica, e quindi anche la spiegazione del perché ciò viene fatto. È un po 'come una situazione di tabulazione contro spazio - tranne per il fatto che una è stata risolta, perché le persone che usano gli spazi piuttosto che le schede, fanno più soldi, secondo StackOverflow ... :-)
shevy

1

Il puntatore è un modificatore del tipo. È meglio leggerli da destra a sinistra per capire meglio come l'asterisco modifica il tipo. 'int *' può essere letto come "puntatore a int '. In più dichiarazioni devi specificare che ogni variabile è un puntatore o verrà creata come variabile standard.

1,2 e 3) Il test è di tipo (int *). Lo spazio bianco non ha importanza.

4,5 e 6) Il test è di tipo (int *). Test2 è di tipo int. Anche in questo caso gli spazi bianchi sono irrilevanti.


-3

Una buona regola pratica, molte persone sembrano afferrare questi concetti: In C ++ molto significato semantico è derivato dall'associazione a sinistra di parole chiave o identificatori.

Prendiamo ad esempio:

int const bla;

La const si applica alla parola "int". Lo stesso vale per gli asterischi dei puntatori, si applicano alla parola chiave a sinistra di essi. E il nome effettivo della variabile? Sì, è dichiarato da ciò che ne resta.


1
Questo non risponde alla domanda. Peggio ancora, se proviamo a dedurne una risposta, significa che l'asterisco si lega al tipo alla sua sinistra, che come tutti hanno detto è falso. Si lega al nome della singola variabile alla sua destra.
underscore_d
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.