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?

Était-ce utile?

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top