Pourquoi sizeof int est faux, alors que sizeof (int) est correct?

96

Nous savons que sizeofc'est un opérateur utilisé pour calculer la taille de n'importe quel type de données et expression, et lorsque l'opérande est une expression, les parenthèses peuvent être omises.

int main()
{
        int a;

        sizeof int;
        sizeof( int );
        sizeof a;
        sizeof( a );

        return 0;
}

le premier usage de sizeofest faux, tandis que d'autres ont raison.

Lorsqu'il est compilé à l'aide de gcc, le message d'erreur suivant s'affiche:

main.c:5:9: error: expected expression before int

Ma question est de savoir pourquoi la norme C ne permet pas ce type d'opération. Provoquera-t-il sizeof intune ambiguïté?

Yishu Fang
la source
5
Le plus drôle est que toutes les expressions ne sont pas acceptées sans parenthèses: essayez sizeof (int)a.
Fred Foo
2
@MikkelK: OP demande le raisonnement derrière les citations standard, il connaît déjà les citations qui sont mentionnées dans la réponse marquée.
Alok Enregistrer
2
@Lundin: sizeof +(int)aa l'avantage *&de compiler réellement ;-)
Steve Jessop
2
@SteveJessop Ah oui, ce n'est pas une lvalue. Bien qu'il ait compilé en Embarcadero C ++, assez curieusement. Quoi qu'il en soit, je crois que nous venons de trouver une utilisation pour l'opérateur unaire +! Ce doit être la première fois dans l'histoire de la programmation C :)
Lundin
2
@Lundin: Vous devez toujours faire attention avec unaire +. Par exemple, en sizeof +(char)a == sizeof(int)raison de la promotion d'entiers, il est probablement moins sujet aux erreurs de simplement mettre entre parenthèses s'il y a un problème avec l'expression dont vous essayez de prendre la taille. Je ne suis donc pas sûr que j'irais jusqu'à l'appeler "une utilisation", même si j'avoue l'avoir utilisé ...
Steve Jessop

Réponses:

101

Ce qui suit peut être ambigu:

sizeof int * + 1

Est-ce que c'est (sizeof (int*)) + 1ou (sizeof(int)) * (+1)?

Évidemment, le langage C aurait pu introduire une règle pour résoudre l'ambiguïté, mais je peux imaginer pourquoi cela n'a pas dérangé. Avec le langage tel qu'il est, un spécificateur de type n'apparaît jamais "nu" dans une expression, et il n'y a donc pas besoin de règles pour déterminer si cette seconde *fait partie du type ou d'un opérateur arithmétique.

La grammaire existante résout déjà l'ambiguïté potentielle de sizeof (int *) + 1. Il est (sizeof(int*))+1, non sizeof((int*)(+1)) .

C ++ a un problème quelque peu similaire à résoudre avec la syntaxe de conversion de style fonction. Vous pouvez écrire int(0)et vous pouvez écrire typedef int *intptr; intptr(0);, mais vous ne pouvez pas écrire int*(0). Dans ce cas, la résolution est que le type "nu" doit être un nom de type simple, il ne peut pas s'agir de n'importe quel ancien identifiant de type pouvant contenir des espaces ou de la ponctuation à la fin. Peut sizeof- être aurait-il pu être défini avec la même restriction, je ne suis pas certain.

Steve Jessop
la source
1
C ++ a new int*(X)ce qui serait ambigu si C ++ ne spécifiait pas que le nouvel opérateur prend la chaîne la plus longue qui pourrait éventuellement être un type. Donc, en C ++, ils auraient pu faire la même chose avec sizeof, je suppose. Mais en C ++, vous pouvez dire sizeof int()ce qui aurait alors été ambigu (type ou valeur initialisé int?).
Johannes Schaub - litb
@ JohannesSchaub-litb: Mmm, alors peut-être que C ++ pourrait dire que le type est préféré s'il est possible d'en analyser un, sinon c'est une expression. L'ambiguïté serait résolue mais sizeof int()serait mal formée («non operator()pour size_t»), ce qui, je pense, ne serait pas le bienvenu!
Steve Jessop
32

À partir de la norme C99

6.5.3.4.2
L' sizeofopérateur donne la taille (en octets) de son opérande, qui peut être une expression ou le nom entre parenthèses d'un type.

Dans votre cas, il intn'y a ni expression ni nom entre parenthèses.

Jainendra
la source
10
Je ne comprends pas pourquoi cela obtient 7 votes positifs. Comme les trois réponses supprimées, il ne fait que répéter la règle au lieu d'expliquer pourquoi la règle existe.
Fred Foo
7
@larsmans, oui, je suis d'accord avec vous. Bien qu'il continue à répéter la règle, mais au moins, il donne un morceau de lecture autorisant.
Yishu Fang
3
@larsmans Si nous essayons de justifier chaque décision prise en C99, nous serons là toute l'année. La citation de la norme est une bonne manière de conclure cette discussion.
Perry
1
@Perry: si vous n'aimez pas ce genre de question, vous pouvez voter pour fermer la question comme argumentative.
Fred Foo
4
En tant que non-praticien du C ++, même je comprends cette réponse, je ne sais pas quel est le problème si vous pouvez lire et comprendre l'anglais.
Kev
6

Il existe deux façons d'utiliser l'opérateur sizeof en C. La syntaxe est la suivante:

C11 6.5.3 Unary operators
...
sizeof unary-expression
sizeof ( type-name )

Chaque fois que vous utilisez un type comme opérande, vous devez avoir la parenthèse, par la définition de syntaxe du langage. Si vous utilisez sizeof sur une expression, vous n'avez pas besoin de la parenthèse.

Le standard C donne un exemple de ce que vous pourriez vouloir utiliser sur une expression:

sizeof array / sizeof array[0]

Cependant, dans un souci de cohérence et pour éviter les bogues liés à la priorité des opérateurs, je conseillerais personnellement de toujours utiliser () quelle que soit la situation.

Lundin
la source
@ JohannesSchaub-litb Je conviens que cela ne fournit aucune justification sur la manière dont le comité de normalisation C a raisonné lorsqu'il a spécifié la norme C90. Il faudrait leur demander ... Il répond sans aucune justification, cependant, C ne le permet pas puisque la syntaxe est celle spécifiée en 6.5.3. Le PO ne semblait pas non plus conscient de la différence entre sizeof expressionet sizeof(type), ce qui est expliqué dans cette réponse.
Lundin
(Pour mémoire, je viens de lire les justifications C90 et C11 et aucun des deux ne fournit d'explication.)
Lundin
Je soupçonne qu'il n'y a pas de justification nécessaire à cela, c'est juste la façon dont les concepteurs C originaux ont décidé de le faire. Peut-être que cela a facilité les choses pour le premier analyseur. J'allais poster une réponse sur le fait que les typedefs et les variables partagent le même espace de noms, mais cela n'empêche pas d'autoriser la première syntaxe; il a juste besoin des règles d'analyse pour dire qu'il préfère la variable quand il n'y a pas de parens, préfère le type quand il y en a, et les deux formes peuvent être utilisées quand le nom est sans ambiguïté. Puisqu'il n'est pas nécessaire de le changer, les comités des normes l'ont laissé tranquille.
Barmar