sizeof prenant deux arguments
-
27-10-2019 - |
Question
Dans C.1.3 du C ++ IS (2003. Il est dans le C ++ 11 est aussi), les points standard sur une différence entre ISO C et C ++; à savoir, pour
char arr[100];
retourne sizeof(0, arr)
sizeof(char*)
en C, mais 100
en C ++.
Je ne trouve aucune documentation pour sizeof
prendre deux arguments. Le repli évident est l'opérateur virgule, mais je ne pense pas: sizeof(arr)
en C est 100
; sizeof(0, arr)
est sizeof(char*)
. Les deux sizeof(0, arr)
et sizeof(arr)
sont 100
en C ++.
Je peux être le manque point de l'ensemble de l'IS dans ce contexte. Quelqu'un peut-il aider? Ceci est similaire à une question discutée en arrière '09, mais personne ne fait référence à la IS, et je ne pense pas a été donné la bonne réponse.
Modifier : En fait, l'IS parle de l'opérateur virgule. Donc, pour une raison (0, arr)
retourne une char*
en C, mais un char[100]
en C ++. Pourquoi?
La solution
En C, le tableau est dépérit à un pointeur, en raison des différentes spécifications de l'opérateur virgule par rapport à rvalues ??et lvalues ??(pas la seule différence de placer un tel peut être trouvé). En C ++, puis les séjours du tableau un tableau, ce qui donne le résultat correct.
Autres conseils
C, virgule opérateur ne produit pas une lvalue, par conséquent, la arr
de matrice qui est une lvalue désintégrations dans un type de pointeur qui est une rvalue (dans ce cas). Alors sizeof(0,arr)
devient équivalent à sizeof(char*)
, en raison de lvalue à rvalue conversion.
Mais en C ++, opérateur virgule produit une lvalue. Il n'y a pas lvalue à rvalue conversion. Donc sizeof(0,arr)
reste la même, ce qui équivaut à sizeof(char[100])
.
Par ailleurs, sizeof
n'est pas une fonction, il est un opérateur. Donc, ce qui suit est complètement valide C ++ (C et, si vous imaginez printf
au lieu de cout
):
int a[100], b[200], c[300], d[400];
cout << sizeof(a,b,c,d) << endl;
Démo: http://www.ideone.com/CtEhn
Vous pourriez penser que je l'ai passé 4 opérandes à sizeof
mais qui ne va pas. sizeof
fonctionne sur le résultat des opérateurs par des virgules. Et sa raison des nombreux opérateurs de virgule que vous voyez beaucoup de opérandes.
4 opérandes avec 3 opérateurs par des virgules; comme dans 1+2+3+4
, il sont 3 opérateurs, 4 opérandes.
ci-dessus est équivalente à la suivante (valable en 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
Démo: http://www.ideone.com/07VNf
Il est donc virgule opérateur qui vous fait sensation qu'il ya beaucoup de arguments . Ici virgule est un opérateur, mais dans l'appel de fonction, virgule est pas un opérateur, son séparateur argument simplement.
function(a,b,c,d); //here comma acts a separator, not operator.
sizeof(a,b,c,d)
fonctionne sur le type du résultat des opérateurs de ,
, exactement de la même manière, sizeof(1+2+3+4)
fonctionne sur le type du résultat des opérateurs de +
.
note également que vous ne peut pas écriture sizeof(int, char, short)
, précisément parce que virgule opérateur ne peut pas fonctionner sur types . Il fonctionne sur la valeur uniquement. Je pense, sizeof
est le seul opérateur en C et C ++, qui peut fonctionner sur types aussi bien. En C ++, il y a un opérateur qui peut plus fonctionne sur types . Son nom est typeid
.
Il est un opérateur virgule. Et la différence dont vous parlez n'a absolument rien à voir avec sizeof
. La différence est vraiment lvalue à rvalue, à pointer tableau et les comportements de désintégration similaires entre C et langues C +.
langue C est plutôt déclencheur heureux à cet égard: les tableaux se désintègrent à des pointeurs pratiquement immédiatement (à l'exception de très peu de contextes spécifiques), ce qui explique pourquoi le résultat de l'expression de 0, arr
est de type char *
. Il est équivalent à 0, (char *) arr
.
Dans les tableaux de langage C de préserver leur « arrayness » beaucoup plus longtemps. Lorsqu'ils sont utilisés dans le cadre de réseaux d'opérateurs de ,
ne se dégrade pas à des pointeurs (et lvalues ??ne se décomposent pas rvalues), ce qui explique pourquoi en C ++ le type d'expression de 0, arr
est encore char[100]
.
Ce qui explique la différence de comportement de sizeof
dans cet exemple. opérateur ?:
est un autre exemple d'un opérateur qui démontre la différence de comportement similaire carie, à savoir sizeof(0 ? arr : arr)
vous donnera des résultats différents en C et C ++. Au fond, tout cela découle du fait que les opérateurs C ne conservent généralement pas la lvalueness de leurs opérandes. Beaucoup d'opérateurs peuvent être utilisés pour illustrer ce comportement.
Ce ne sizeof
prend deux arguments. sizeof
est un opérateur, pas une fonction.
Considérez que (0, arr)
est une expression en utilisant l'opérateur virgule, et tout le reste tombe en place.
sizeof
ne prend pas deux arguments. Mais ce n'est pas une fonction, non plus,
de sorte que le (...)
ne délimite pas les arguments de la fonction, ils sont juste un
en option une partie de la syntaxe, et forcer le regroupement. Lorsque vous écrivez
sizeof(0, arr)
, l'argument de sizeof
est le 0,
arr
d'expression unique. Une seule expression avec un opérateur virgule, qui évalue la
expression à gauche de la virgule, jette sa valeur (mais pas son
effets secondaires), évalue alors l'expression à la droite de la virgule,
et utilise sa valeur comme la valeur de l'expression complète.
Je ne suis pas sûr de C, mais cela pourrait être une différence entre la
langauges. En C ++, la conversion tableau à pointeur ne se produit pas à moins que
il est nécessaire; en C, si je me souviens bien, la norme indique que
toujours a lieu, sauf dans certains contextes. Y compris comme
opérateur de sizeof
. Dans ce cas, étant donné que l'opérateur virgule ne
ont une contrainte en ce qui concerne les types de ses opérandes, la
conversion tableau à pointeur ne se fait pas en C ++. un en C,
operatand de l'opérateur virgule ne figure pas dans les exceptions, de sorte que le
conversion tableau à pointeur ne ont lieu. (Dans ce cas, le tableau
est un opérande de l'opérateur virgule, et non de sizeof
).
La meilleure façon de voir ce qui pourrait se passer ici est de regarder à la grammaire dans la norme. Si nous examinons le projet de norme section C99 6.5.3
Les opérateurs unaires paragraphe 1 nous pouvons voir que la grammaire pour sizeof est:
sizeof unary-expression
sizeof ( type-name )
Ainsi, le second ne s'applique pas, mais comment le sizeof unary-expression
applique dans ce cas? Si nous regardons la section A.2.1
Expressions du projet de norme et de travail à travers la grammaire comme ceci:
unary-expression -> postfix-expression -> primary-expression -> ( expression )
nous obtenons les parenthesizes autour d'une expression et maintenant nous avons juste à regarder la grammaire pour opérateur virgule de la section 6.5.17
opérateur Comma et nous voyons:
expression:
assignment-expression
expression , assignment-expression
Nous avons donc maintenant:
sizeof( expression , assignment-expression )
^
|
comma operator
les deux expression et expression d'affectation peut nous emmener à primaire expression qui a la grammaire suivante:
primary-expression:
identifier
constant
string-literal
( expression )
et 0
est constante et arr
est un identifiant nous avons donc:
sizeof( constant , identifier )
Alors qu'est-ce que le opérateur virgule faire ici? Section 6.5.17
paragraphe 2 dit:
L'opérande gauche d'un opérateur virgule est évalué comme une expression vide; Il y a un Point de séquence après son évaluation. Ensuite, l'opérande de droite est évaluée; le résultat a son type et de valeur. 97)
puisque l'opérateur virgule n'est pas une des exceptions où un tableau n'est pas converti en un pointeur, il donne un pointeur ( c'est couvert dans la section 6.3.2.1
lvalues, les tableaux et les désignateurs de fonction ) qui signifie que nous retrouvons avec:
sizeof( char * )
C ++ la grammaire est assez similaire si nous nous retrouvons au même endroit, mais les opérateurs par des virgules fonctionne différemment. Le C ++ projet de norme section 5.18
opérateur Comma dit:
[...] Le type et la valeur du résultat sont le type et la valeur du droit opérande; le résultat est de la même catégorie de valeur que son opérande droit [...]
et à pointer tableau conversion ne pas nécessaire et si nous nous retrouvons avec:
sizeof( char[100] )
Comme plusieurs ont déjà dit, et je veux ajouter qu'une seule chose, est sizeof une prise de l'opérateur soit une expression ou une expression coulée. Pour cette raison, je pris l'habitude d'écrire à une sizeof parenthèse uniquement si elle est une expression de casting.
char *arr;
struct xxx { ... } v;
Je vais écrire
sizeof arr
sizeof v
sizeof (struct xxx) /* Note the space after the sizeof, it's important */
sizeof (char *)
Je fais la même chose avec return
pas entre parenthèses, car il n'est pas un appel de fonction, et si je mets entre parenthèses c'est parce que l'expression suivante les besoins.