2010-08-21 9 views
6

Ho alcune domande sul collegamento dalle seguenti variabili. Con esempi di 7.1.1/7 di C++ 03 e la sperimentazione di compilatori (Comeau, clang e GCC), sono venuto ai seguenti tipi di collegamento:Collegamento di varie variabili const/statiche

  1. Prima static, quindi extern

    static int a; // (a) 
    extern int a; // (b) valid, 'a' still internal 
    

    Mi è chiaro secondo la sezione 3.5: (a) implica il collegamento interno. E (b) implica anche il collegamento interno, perché il nome "a" è dichiarato statico (da (a)).

  2. primo extern, quindi static

    extern int b; // (c) 
    static int b; // (d) invalid! 
    

    First, (c) implica linkage esterno. Ma (d) implica il collegamento interno perché il nome "b" è dichiarato statico con (d). Questo non è valido secondo 7.1.1/7, poiché il collegamento implicito non è coerente.

  3. primo const, quindi extern

    const double pi1 = 3.14; // (e) 
    extern const double pi1; // (f) valid and 'pi1' is internal 
    

    First, (e) implica collegamento interno, perché è const, né dichiarato extern espressa o implicita precedentemente linkage esterno. E (f) dovrebbe implicare il collegamento extern ed essere un errore, perché dichiara esplicitamente il nome extern, ma i compilatori lo mantengono interno! Perché così?Questa è la mia domanda.

  4. Prima extern, quindi const

    extern const double pi2; // (g) 
    const double pi2 = 3.14; // (h) valid and 'pi2' is external 
    

    Ora, (g) implica collegamento esterno perché abbiamo esplicitamente dichiarato extern. E (h) implica anche il collegamento esterno perché (g) dichiarato esplicitamente extern.


ho sperimentalmente scoperto il collegamento per 3 e 4 con il seguente modello (il secondo argomento deve avere collegamento esterno)

template<typename T, T&> struct ensure { }; 

ensure<const double, pi1> e1; // failed 
ensure<const double, pi2> e2; // succeeded 

Sommario: La discussione con Charles Bailey si è rivelata abbastanza fruttuosa e ha mostrato che ci sono due possibili interpretazioni di 3.5/3, dove l'importa letture nt punto elenco

Un nome con ambito namespace (3.3.5) presenta il collegamento interno se è il nome di

  • un oggetto o riferimento che viene dichiarata esplicitamente const e extern né esplicitamente né dichiarato precedentemente dichiarati in collegamento esterno;

Se guardiamo al punto (f), quindi le due interpretazioni arrivano a conclusioni diverse, come illustrato di seguito

  1. La prima interpretazione osserva che pi1 è dichiarato const ma è anche dichiarata extern. La variabile ha quindi il collegamento esterno.

  2. La seconda interpretazione interpreta entrambe le occorrenze di "dichiarato" per fare riferimento alla stessa dichiarazione. In questo modo, significa che è dichiarato const, ma non extern const. Notiamo che (e) è dichiarato const e non extern const, pertanto viene fornito il collegamento interno pi1.

Ora, quale interpretazione è corretta? Non riesco a determinare da quella dicitura, ma i compilatori sembrano interpretare questo secondo modo. In particolare, se prendiamo la prima interpretazione, l'ultima parte citata di 3.5/3 sarebbe superflua, perché non ci sarebbe uno scenario valido in cui un nome sarebbe dichiarato const e dichiarato in precedenza con linkage esterno ma senza un esplicito extern.

+1

Forse mi manca qualcosa, ma 3 non è uguale a 1? (Cioè, il nome 'pi1' è 'dichiarato statico' per così dire?). Anche se suppongo di aver semplicemente pregato perché 4 non sia valido. – GManNickG

+0

@GMan, vedi 3.5/3 per questi due casi. Sono gestiti da diversi punti elenco. –

+0

@GMan per 4, il primo lo rende esterno e il secondo non lo rende interno, perché il nome è stato dichiarato esplicitamente esterno (dalla prima dichiarazione). Quindi, sia solo il primo, sia il primo e il secondo insieme implicano lo stesso collegamento. Per 2, solo il primo implica il collegamento esterno, ma il primo e il secondo insieme implicano il collegamento interno perché il nome è esplicitamente dichiarato statico dal secondo. Quindi non è valido. –

risposta

4
const double pi1 = 3.14; // (e) 
extern const double pi1; // (f) valid and 'pi1' is internal 

La mia interpretazione è la seguente. Quando si considera il collegamento di un nome, consideriamo le dichiarazioni precedenti e quella che viene interpretata in questo punto del parsing. Questo è il motivo per cui static int a; extern int a; è OK, ma non lo è extern int b; static int b;.

All'incontro con la prima dichiarazione, notiamo che è dichiarato esplicitamente const ma che non è stato dichiarato esplicitamente extern né dichiarato in precedenza per il collegamento esterno. Ciò corrisponde a una delle opzioni di 3.5/2, pertanto pi1 ha un collegamento interno.

All'incontro con la seconda dichiarazione chiediamo è pi1 il nome di un oggetto che è esplicitamente dichiarato const ma né esplicitamente dichiarato extern né [... blah ...]. Io sostengo che è perché è stato così dichiarato al punto (e).Certo, non è dichiarato in questo modo ovunque ma allo stesso modo a era il nome di un oggetto dichiarato static quando stavamo considerando la dichiarazione extern int a; anche se non è stata dichiarata static ovunque. Questo, per me, significa che la dichiarazione (f) non implica un diverso collegamento dalla dichiarazione (e).

+0

Penso che la tua interpretazione abbia un senso. Ora penso che lo standard dice che è dichiarato esplicitamente const, ma non "extern const". Perché altrimenti il ​​testo successivo "né precedentemente dichiarato di avere un collegamento esterno"; sarebbe superfluo: la dichiarazione che usa "const" ma non "extern" sarà una definizione, ma per essere ben formata, qualsiasi altra dichiarazione * avrà * di usare "extern" allora. Solo nell'interpretazione "extern const", che applichi penso, il testo aggiuntivo non è superfluo. –

+0

Ho cambiato la mia domanda per riassumere le nostre scoperte e accetterò questa. –

0

Penso che in # 3 tu abbia commesso un errore nella tua analisi. Per quanto ne so, const non implica nulla sul collegamento. Non sono sicuro di come stai arrivando alla conclusione che il compilatore rende il collegamento interno. La maggior parte dei compilatori sostituirà (come ottimizzazione) tutti i riferimenti alla variabile const con il valore a cui è stato inizializzato, quindi il simbolo potrebbe non apparire affatto nel codice.

E anche se non l'hai fatto, è chiaro dal # 1 che se qualcosa con collegamento interno viene successivamente dichiarato con la parola chiave extern che rimane con il collegamento interno. Quindi non so perché ti aspetteresti un errore.

E se il collegamento interno implicito const, quindi # 4 dovrebbe essere un errore per lo stesso motivo # 2 è.

+2

'const' implica il collegamento interno. 7.1.1/6: "Un nome dichiarato in uno scope namespace senza uno _storage-class-specifier_ ha un collegamento esterno a meno che non abbia linkage interno a causa di una precedente dichiarazione e a condizione che non sia dichiarato' const'. Oggetti dichiarati 'const' e non dichiarato esplicitamente che 'extern' ha un collegamento interno." –

0

Avere entrambi (e) e (f) nello stesso spazio dei nomi è semplicemente invalido, da §7.1.1/7 "I collegamenti impliciti dalle dichiarazioni successive per una data entità devono essere d'accordo.".

Questa regola richiede una diagnostica.

Tuttavia, almeno Comeau Online non diagnostica la violazione.

Acclamazioni & hth,

EDIT:. He he, alzai gli occhi DR 426, come detto in un'altra risposta qui, e sembra chi ha redatto la proposta di risoluzione, il che rende UB invece di diagnosticabile, erano non a conoscenza di §7.1.1/7. Non ho intenzione di commentare il problema o di sollevarlo in comp.std.C++ perché ho trovato che il lavoro di standardizzazione è troppo politico e privo di senso (argomenti mumbo-jumbo) per me. Ma in entrambi i casi, il codice non è valido.

+0

Cosa intendi con "argomenti mumbo jumbo"? –

+0

@Johannes: ad es. l'argomento secondo cui per coerenza un loop infinito do-nothing dovrebbe essere UB. O l'argomento secondo cui spostare gli op dovrebbe essere permesso di lanciare (non riesco a ricordare quale fosse l'argomento). Presto. Saluti, –