2012-04-04 12 views
38

C++ 03 5.1 espressioni primarie
§2:
Perché i valori stringa sono l-valore mentre tutti gli altri valori letterali sono valore-r?

Un letterale è un'espressione primaria. Il suo tipo dipende dalla sua forma (2.13). Una stringa letterale è un lvalue; tutti gli altri valori letterali sono rvalues.

Qual è la logica alla base di questo?
Come ho capito, i valori letterali di stringa sono oggetti, mentre tutti gli altri valori letterali non lo sono. E un valore l fa sempre riferimento a un oggetto.

Ma la domanda quindi è perché gli oggetti letterali stringa non sono tutti gli altri letterali?
Questa logica mi sembra più un problema di uovo o di pollo.

Capisco che la risposta a questo possa essere correlata all'architettura hardware piuttosto che C/C++ come linguaggi di programmazione, tuttavia mi piacerebbe sentire lo stesso.

Nota: Sono Tagging questa domanda c & C++ sia perché serie C99 ha anche citazioni simili, in particolare §6.5.1.4

+2

I valori non sono oggetti. Gli Lvalue sono valori che possono apparire sul lato sinistro di un compito, come variabili, membri di strutture e ricerche di elementi dell'array. (L = Left.) – duskwuff

+6

@duskwuff: Il Comitato chiede di dissentire. Per 6.3.2.1, "Un lvalue è un'espressione con un tipo di oggetto o un tipo incompleto diverso da void, se un lvalue non designa un oggetto quando viene valutato, il comportamento non è definito." Per la nota a piè di pagina (53) citata in quella citazione, un lvalue dovrebbe essere considerato come un "valore di localizzatore di oggetti". –

+0

@JohnCalsbeek C++ 11 'risolto', ad es. 'alias {}' è ora possibile. 'U {} .arr' è anche un valore per il tipo di matrice se' arr' è dichiarato come tale nella definizione di classe per 'U'. –

risposta

24

Una stringa letterale è un letterale con il tipo di matrice, e in C c'è nessun modo per un tipo di matrice di esistere in un'espressione tranne che come un valore di lvalue. I valori letterali delle stringhe potevano essere specificati per avere il tipo di puntatore (piuttosto che il tipo di array che di solito decompone a un puntatore) che punta alla stringa "contenuti", ma questo li renderebbe piuttosto meno utili; in particolare, non è stato possibile applicare l'operatore sizeof.

Si noti che C99 ha introdotto letterali composti, che sono anche lvalue, quindi avere un valore letterale come un lvalue non è più un'eccezione speciale; è più vicino all'essere la norma.

+0

Non è 'puts (" ciao ")' un esempio di un'espressione con un tipo di matrice che potrebbe essere un valore? – Pubby

+1

'puts (" ciao ")' è un'espressione con tipo 'int'. –

+0

Intendevo dove "ciao" è un valore. – Pubby

6

Direi che il motivo originale era principalmente pragmatico: una stringa letterale deve risiedere nella memoria e avere un indirizzo. Il tipo di una stringa letterale è un tipo di matrice (char[] in C, char const[] in C++) e i tipi di matrice vengono convertiti in puntatori nella maggior parte dei contesti. La lingua potrebbe aver trovato altri modi per definire questo (ad esempio una stringa letterale potrebbe avere il tipo di puntatore per iniziare, con regole speciali relative a ciò a cui punta , ma semplicemente rendendo letterale un lvalue è probabilmente il modo più semplice di definire ciò che è concretamente necessario.

+0

Perché il voto negativo per quella che è quasi sicuramente la risposta corretta? –

+0

Non è il mio downvote. Quindi, se comprendo correttamente la tua risposta, la commissione ha appena accettato ciò che è stato probabilmente suggerito senza indagare sul fatto che fosse l'approccio migliore possibile, ma solo che sembrava più flessibile scegliere all'epoca? –

+0

Per quello che vale, lo standard C99 ha appena preso il testo dallo standard C89 e nel processo di standardizzazione C89, come ricordo (dalla lettura dei minuti, non sono mai stato in nessuna riunione) ci sono state alcune discussioni minori su questo, ma mai andato da nessuna parte I grandi argomenti infuocati riguardavano la creazione di string letterali 'const'. – torek

7

Un lvalue in C++ non si riferisce sempre a un oggetto. Può riferirsi anche a una funzione. Inoltre gli oggetti non devono essere indicati da lvalue. Possono essere indicati dai rvalue, incluso per gli array (in C++ e C). Tuttavia, nella vecchia C89, la conversione da matrice a puntatore non si applicava agli array rvalue.

Ora, un valore di rvalore indica una durata illimitata, limitata o prossima alla scadenza. Una stringa letterale vive comunque per l'intero programma.

Quindi i valori letterali delle stringhe essendo lvalue hanno esattamente ragione.

+0

Che ne dici della vita dei letterali integrali? E come si farebbe comunque ad indirizzarli se il loro indirizzo non può essere preso? I letterali interi –

+2

non si riferiscono a un oggetto, pertanto non è necessario prendere in considerazione una durata. –

7

I valori letterali delle stringhe sono array - oggetti di dimensioni intrinsecamente imprevedibili (cioè di dimensioni definite dall'utente e possibilmente di grandi dimensioni). In generale, non c'è altro modo di rappresentare tali letterali se non come oggetti in memoria, cioè come lvalue.Nel C99 ciò vale anche per i valori letterali composti, che sono anche valori l.

Qualsiasi tentativo di nascondere artificialmente il fatto che i valori letterali delle stringhe sono lvalue a livello di linguaggio produrrebbe un numero considerevole di difficoltà completamente inutili, poiché la possibilità di puntare a una stringa letterale con un puntatore e alla possibilità di accedervi poiché un array si basa in modo critico sul fatto che la sua lvalore è visibile a livello di linguaggio.

Nel frattempo, i valori letterali dei tipi scalari hanno dimensioni fisse in fase di compilazione. Allo stesso tempo, è molto probabile che tali valori letterali siano incorporati direttamente nei comandi della macchina sulla specifica architettura hardware. Ad esempio, quando si scrive qualcosa come i = i * 5 + 2, i valori letterali 5 e 2 diventano parti esplicite (o anche implicite) del codice macchina generato. Non esistono e non hanno bisogno di esistere come posizioni autonome nell'archiviazione dei dati. Non è necessario archiviare i valori 5 e 2 nella memoria di dati.

E 'anche da notare che in molti (se non la maggior parte, o tutti) architetture hardware letterali in virgola mobile sono in realtà implementate come lvalue "nascosti" (anche se la lingua non li espone come tali). Su piattaforme come i comandi macchina x86 di un gruppo in virgola mobile non supportano operandi immediati incorporati. Ciò significa che virtualmente ogni letterale a virgola mobile deve essere memorizzato dal compilatore (e letto dalla memoria dati). Per esempio. quando si scrive qualcosa di simile i = i * 5.5 + 2.1 si traduce in qualcosa di simile

const double unnamed_double_5_5 = 5.5; 
const double unnamed_double_2_1 = 2.1; 
i = i * unnamed_double_5_5 + unnamed_double_2_1; 

In altre parole, letterali in virgola mobile, spesso finiscono per diventare lvalue "non ufficiali" internamente. Tuttavia, è perfettamente logico che le specifiche del linguaggio non abbiano tentato di esporre questo dettaglio di implementazione. A livello linguistico, i letterali aritmetici hanno più senso come valori rituali.

Problemi correlati