sizeof prendere due argomenti
-
27-10-2019 - |
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é?
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.