Domanda

In C.1.3 di C ++ IS (2003. È anche in C ++ 11 IS), lo standard evidenzia una differenza tra ISO C e C ++;vale a dire, per

char arr[100];

sizeof(0, arr) restituisce sizeof(char*) in C, ma 100 in C ++.

Non riesco a trovare alcuna documentazione per sizeof che accetta due argomenti.L'ovvio fallback è l'operatore virgola, ma non credo sia così: sizeof(arr) in C è 100;sizeof(0, arr) è sizeof(char*).Sia sizeof(0, arr) che sizeof(arr) sono 100 in C ++.

Potrei perdere l'intero punto dell'IS in questo contesto.Qualcuno può aiutare?È simile a una domanda discussa nel '09, ma nessuno ha fatto riferimento all'IS e non credo che sia stata data la risposta corretta.


Modifica : in realtà, IS sta parlando dell'operatore virgola.Quindi, per qualche motivo (0, arr) restituisce un char* in C, ma un char[100] in C ++.Perché?

È stato utile?

Soluzione

In C quindi l'array decade in un puntatore, a causa della diversa specifica dell'operatore virgola in relazione a rvalues e lvalues (non l'unico posto in cui è possibile trovare una tale differenza).In C ++ l'array rimane un array, producendo il risultato corretto.

Altri suggerimenti

In C, l'operatore virgola non produce un lvalue, di conseguenza l'array arr che è un lvalue decade in un tipo di puntatore che è un rvalue (in questo caso). Quindi sizeof(0,arr) diventa equivalente a sizeof(char*), a causa della conversione lvalue-to-rvalue .

Ma in C ++, l'operatore virgola produce un lvalue. Non esiste alcuna conversione da lvalue a rvalue . Quindi sizeof(0,arr) rimane lo stesso, che è equivalente a sizeof(char[100]).

A proposito, sizeof non è una funzione, è un operatore. Quindi quanto segue è C ++ completamente valido (e C, se immagini printf invece di cout):

int a[100], b[200], c[300], d[400];
cout << sizeof(a,b,c,d) << endl;

Demo: http://www.ideone.com/CtEhn

Potresti pensare che ho passato 4 operandi a sizeof ma è sbagliato. sizeof opera sul risultato degli operatori virgola. Ed è a causa dei molti operatori virgola che vedi molti operandi.

4 operandi con 3 operatori virgola; proprio come in 1+2+3+4, ci sono 3 operatori, 4 operandi.

Quanto sopra è equivalente al seguente (valido in C ++ 0x):

auto & result = (a,b,c,d); //first all comma operators operate on the operands.
cout << sizeof (result) << endl; //sizeof operates on the result

Demo: http://www.ideone.com/07VNf

Quindi è l'operatore virgola che ti fa sentire che ci sono molti argomenti . Qui virgola è un operatore, ma nella chiamata di funzione, virgola NON è un operatore, il suo semplice separatore di argomenti.

function(a,b,c,d); //here comma acts a separator, not operator.

Quindi sizeof(a,b,c,d) opera sul tipo del risultato degli operatori ,, esattamente allo stesso modo, sizeof(1+2+3+4) opera sul tipo del risultato degli operatori +.

Tieni inoltre presente che non puoi scrivere sizeof(int, char, short), proprio perché l'operatore virgola non può operare sui tipi . Funziona solo su valore . Penso che sizeof sia l'unico operatore in C e C ++, che può operare anche sui tipi . In C ++, c'è un altro operatore che può operare sui tipi . Il suo nome è typeid.

È un operatore virgola. E la differenza di cui parli non ha assolutamente nulla a che fare con sizeof. La differenza è davvero nei comportamenti di decadimento lvalue-to-rvalue, array-to-pointer e simili tra i linguaggi C e C ++.

Il linguaggio C a questo proposito è piuttosto innescabile: gli array decadono in puntatori praticamente immediatamente (con l'eccezione di pochissimi contesti specifici), motivo per cui il risultato dell'espressione 0, arr ha il tipo char *. È equivalente a 0, (char *) arr.

Nel linguaggio C ++ gli array conservano la loro "arrayness" molto più a lungo. Quando vengono utilizzati nel contesto di array di operatori , non decadono in puntatori (e i valori l non decadono in rvalues), motivo per cui in C ++ il tipo di espressione 0, arr è ancora char[100].

Questo è ciò che spiega la differenza nel comportamento di sizeof in quell'esempio. L'operatore ?: è un altro esempio di un operatore che dimostra la differenza simile nel comportamento di decadimento, ovvero sizeof(0 ? arr : arr) ti darà risultati diversi in C e C ++. Fondamentalmente, tutto deriva dal fatto che gli operatori C di solito non preservano la validità dei loro operandi. È possibile utilizzare molti operatori per dimostrare questo comportamento.

Questo non è sizeof che accetta due argomenti.sizeof è un operatore, non una funzione.

Considera che (0, arr) è un'espressione che utilizza l'operatore virgola e tutto il resto va a posto.

sizeof non accetta due argomenti. Ma non è nemmeno una funzione quindi il (...) non delimita gli argomenti della funzione, sono solo un file parte facoltativa della sintassi e impone il raggruppamento. Quando scrivi sizeof(0, arr), l'argomento di sizeof è la singola espressione 0, arr. Una singola espressione con un operatore virgola, che valuta il espressione a sinistra della virgola, espelle il suo valore (ma non il suo effetti collaterali), quindi valuta l'espressione a destra della virgola, e utilizza il suo valore come valore dell'espressione completa.

Non sono sicuro di C, ma questa potrebbe essere una differenza tra langauges. In C ++, la conversione da matrice a puntatore non avviene a meno che è necessario; in C, se ricordo bene, lo standard lo dice si svolge sempre tranne che in determinati contesti. Compreso come il operatore di sizeof. In questo caso, poiché l'operatore virgola non lo fa hanno dei vincoli per quanto riguarda i tipi dei suoi operandi, il la conversione da matrice a puntatore non avviene in C ++. In C, an l'operatando dell'operatore virgola non è elencato nelle eccezioni, quindi il la conversione da matrice a puntatore avviene. (In questo caso, il file array è un operando dell'operatore virgola e non di sizeof.)

Il modo migliore per vedere cosa potrebbe succedere qui è guardare la grammatica nello standard. Se guardiamo la bozza della sezione standard C99 6.5.3 Operatori unari paragrafo 1 possiamo vedere che la grammatica per sizeof è:

sizeof unary-expression
sizeof ( type-name )

Quindi il secondo non si applica, ma come si applica il sizeof unary-expression in questo caso? Se guardiamo la sezione A.2.1 Espressioni dalla bozza di standard e lavoriamo sulla grammatica in questo modo:

unary-expression -> postfix-expression -> primary-expression -> ( expression )

otteniamo le parentesi attorno a una espressione e ora dobbiamo solo guardare la grammatica per l ' operatore virgola dalla sezione 6.5.17 operatore virgola e vediamo:

expression:
  assignment-expression
  expression , assignment-expression

Quindi ora abbiamo:

sizeof( expression , assignment-expression )
                   ^
                   |
                   comma operator

sia espressione che espressione-assegnazione possono portarci a espressione-primaria che ha la seguente grammatica:

primary-expression:
  identifier
  constant
  string-literal
  ( expression )

e 0 è una costante e arr è un identificatore quindi abbiamo:

 sizeof( constant , identifier )

Allora cosa fa l ' operatore virgola qui? Il paragrafo 6.5.17 della sezione 2 dice:

L'operando sinistro di un operatore virgola viene valutato come un'espressione void; c'è un punto della sequenza dopo la sua valutazione. Quindi viene valutato l'operando destro; il risultato ha il suo tipo e valore. 97)

poiché l'operatore virgola non è una delle eccezioni in cui un array non viene convertito in un puntatore, restituisce un puntatore ( questo è trattato nella sezione 6.3.2.1 Lvalori, array e designatori di funzione ) il che significa che ci ritroviamo con:

sizeof( char * )

In C ++ la grammatica è abbastanza simile, quindi finiamo nello stesso punto ma gli operatori virgola funzionano in modo diverso. La sezione standard della bozza C ++ 5.18 Operatore virgola dice:

[...] Il tipo e il valore del risultato sono il tipo e il valore dell'operando destro; il risultato è della stessa categoria di valori del suo operando destro [...]

so e la conversione da matrice a puntatore non è richiesta e quindi ci ritroviamo con:

sizeof( char[100] ) 

Come molti hanno già detto, e voglio aggiungere solo una cosa, sizeof è un operatore che prende un'espressione o un'espressione cast. Per questo motivo ho preso l'abitudine di scrivere una parentesi con una dimensione di solo se è un'espressione cast.

 char *arr;
 struct xxx { ... } v;

Scriverò

sizeof arr 
sizeof v

ma

sizeof (struct xxx)       /* Note the space after the sizeof, it's important */
sizeof (char *)

Faccio lo stesso con return senza parentesi, poiché non è una chiamata di funzione, e se metto parentesi è perché l'espressione che segue ne ha bisogno.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top