Je ne suis peut-être pas de cette planète, mais il me semble que ce qui suit devrait être une erreur de syntaxe:
int a[] = {1,2,}; //extra comma in the end
Mais ce n'est pas. J'ai été surpris lorsque ce code a été compilé sur Visual Studio, mais j'ai appris à ne pas faire confiance au compilateur MSVC en ce qui concerne les règles C ++, j'ai donc vérifié la norme et elle est également autorisée par la norme. Vous pouvez voir 8.5.1 pour les règles de grammaire si vous ne me croyez pas.
Pourquoi est-ce autorisé? C'est peut-être une stupide question inutile, mais je veux que vous compreniez pourquoi je pose la question. S'il s'agissait d'un sous-cas d'une règle de grammaire générale, je comprendrais - ils ont décidé de ne pas rendre la grammaire générale plus difficile simplement pour interdire une virgule redondante à la fin d'une liste d'initialisation. Mais non, la virgule supplémentaire est explicitement autorisée. Par exemple, il n'est pas autorisé d'avoir une virgule redondante à la fin d'une liste d'arguments d'appel de fonction (lorsque la fonction prend ...
), ce qui est normal .
Donc, encore une fois, y a-t-il une raison particulière pour laquelle cette virgule redondante est explicitement autorisée?
la source
;
quand il est clair que le prochain jeton est en fait une prochaine déclaration.for()
par exemple), l'ajouter lève un avertissement du compilateur.if (x = 1)
n'est pas ambigu dans la grammaire, mais il est très ambigu pour les humains, et lance donc un avertissement.if
exemple n'est pas ambigu non plus. Je ne pense pas que "ambigu" signifie ce que vous pensez que cela signifie!Réponses:
Il facilite la génération de code source, ainsi que l'écriture de code qui peut être facilement étendu ultérieurement. Considérez ce qui est nécessaire pour ajouter une entrée supplémentaire à:
... vous devez ajouter la virgule à la ligne existante et ajouter une nouvelle ligne. Comparez cela avec le cas où les trois ont déjà une virgule après, où il vous suffit d'ajouter une ligne. De même, si vous souhaitez supprimer une ligne, vous pouvez le faire sans vous soucier de savoir s'il s'agit de la dernière ligne ou non, et vous pouvez réorganiser les lignes sans tripoter les virgules. Fondamentalement, cela signifie qu'il y a une uniformité dans la façon dont vous traitez les lignes.
Pensez maintenant à générer du code. Quelque chose comme (pseudo-code):
Pas besoin de vous soucier de savoir si l'élément actuel que vous écrivez est le premier ou le dernier. Beaucoup plus simple.
la source
C'est utile si vous faites quelque chose comme ceci:
la source
var a = [1, 2,];
:, tout comme la plupart des autres langages que je connais ... ActionScript, Python, PHP.undefined
.Facilité d'utilisation pour le développeur, je pense.
De plus, si pour une raison quelconque, vous disposiez d'un outil qui générait du code pour vous; l'outil n'a pas à se soucier de savoir s'il s'agit du dernier élément de l'initialisation ou non.
la source
J'ai toujours supposé qu'il était plus facile d'ajouter des éléments supplémentaires:
devient simplement:
à une date ultérieure.
la source
[1,2,3,]
est OK mais{a:1, b:2, c:3,}
ne l'est pas).Tout ce que tout le monde dit à propos de la facilité d'ajouter / supprimer / générer des lignes est correct, mais le véritable endroit où cette syntaxe brille est lors de la fusion de fichiers source. Imaginez que vous avez ce tableau:
Et supposez que vous avez archivé ce code dans un référentiel.
Ensuite, votre copain le modifie, ajoutant à la fin:
Et vous l'éditez simultanément, en ajoutant au début:
Sémantiquement, ces types d'opérations (ajout au début, ajout à la fin) devraient être entièrement sécurisés par fusion et votre logiciel de versioning (avec un peu de chance git) devrait pouvoir émerger automatiquement. Malheureusement, ce n'est pas le cas car votre version n'a pas de virgule après le 9 et celle de votre copain. Alors que, si la version originale avait le 9 de fin, ils auraient fusionné automatiquement.
Donc, ma règle de base est: utilisez la virgule de fin si la liste s'étend sur plusieurs lignes, ne l'utilisez pas si la liste est sur une seule ligne.
la source
Je pense que la virgule de fin est autorisée pour des raisons de compatibilité descendante. Il y a beaucoup de code existant, principalement généré automatiquement, qui met une virgule de fin. Cela facilite l'écriture d'une boucle sans condition particulière à la fin. par exemple
Il n'y a pas vraiment d'avantage pour le programmeur.
PS Bien qu'il soit plus facile de générer automatiquement le code de cette façon, j'ai toujours pris soin de ne pas mettre la virgule de fin, les efforts sont minimes, la lisibilité est améliorée, et c'est plus important. Vous écrivez du code une fois, vous le lisez plusieurs fois.
la source
int a = b + c +;
ouif(a && b &&);
il sera plus facile de simplement copier-coller quoi que ce soit à la fin et plus facile d'écrire des générateurs de code. Ce problème est à la fois trivial et subjectif, dans de tels cas, il est toujours bon de faire ce qui est le mieux pour le lecteur de code.&&
opérateur, parfois je fais des conditions commeif (true \n && b1 \n && b2)
pour pouvoir ajouter et supprimer des lignes selon mes besoins.Une des raisons pour lesquelles cela est autorisé à ma connaissance est qu'il devrait être simple de générer automatiquement du code; vous n'avez besoin d'aucune manipulation spéciale pour le dernier élément.
la source
Il facilite les générateurs de code qui crachent des tableaux ou des énumérations.
Imaginer:
C'est-à-dire, pas besoin de faire une manipulation spéciale du premier ou du dernier élément pour éviter de cracher la virgule de fin.
Si le générateur de code est écrit en Python, par exemple, il est facile d'éviter de cracher la virgule de fin en utilisant la
str.join()
fonction:la source
Je suis surpris après tout ce temps, personne n'a cité le manuel de référence annoté C ++ ( ARM ), il dit ce qui suit à propos de [dcl.init] avec emphase:
bien que la grammaire ait évolué depuis que ARM a été écrit, l'origine demeure.
et nous pouvons aller à la justification C99 pour voir pourquoi cela a été autorisé en C et il dit:
la source
Je vois un cas d'utilisation qui n'a pas été mentionné dans d'autres réponses, nos macros préférées:
L'ajout de macros pour gérer en dernier
,
serait très pénible. Avec ce petit changement de syntaxe, cela est trivial à gérer. Et cela est plus important que le code généré par la machine, car il est généralement beaucoup plus facile de le faire dans la langue complète de Turing que le préprocesseur très limité.la source
Le seul langage où il est - en pratique * - non autorisé est Javascript, et il provoque une quantité innombrable de problèmes. Par exemple, si vous copiez et collez une ligne du milieu du tableau, collez-la à la fin et oubliez de supprimer la virgule, votre site sera totalement interrompu pour vos visiteurs IE.
* En théorie, il est autorisé mais Internet Explorer ne suit pas la norme et le traite comme une erreur
la source
var x = [,,,]
est légal (sauf dans IE <9, mais la spécification dit que c'est légal)C'est plus facile pour les machines, c'est-à-dire l'analyse et la génération de code. C'est aussi plus facile pour les humains, c'est-à-dire la modification, la mise en commentaire et l'élégance visuelle via la cohérence.
En supposant C, écririez-vous ce qui suit?
Non. Non seulement parce que la déclaration finale est une erreur, mais aussi parce qu'elle est incohérente. Alors pourquoi faire de même avec les collections? Même dans les langues qui vous permettent d'omettre les derniers points-virgules et virgules, la communauté n'aime généralement pas cela. La communauté Perl, par exemple, ne semble pas aimer omettre les points-virgules, sauf les lignes simples. Ils l'appliquent également aux virgules.
N'omettez pas de virgules dans les collections multilignes pour la même raison que vous ne supprimez pas les points-virgules pour les blocs de code multilignes. Je veux dire, vous ne le feriez pas même si la langue le permettait, non? Droite?
la source
La raison est banale: facilité d'ajout / suppression de lignes.
Imaginez le code suivant:
Maintenant, vous pouvez facilement ajouter / supprimer des éléments à la liste sans avoir à ajouter / supprimer parfois la virgule de fin.
Contrairement à d'autres réponses, je ne pense pas vraiment que la facilité de génération de la liste soit une raison valable: après tout, il est trivial que le code casse la dernière (ou la première) ligne. Les générateurs de code sont écrits une seule fois et utilisés plusieurs fois.
la source
Il permet à chaque ligne de suivre le même formulaire. Tout d'abord, cela facilite l'ajout de nouvelles lignes et la mise en place d'un système de contrôle de version qui suit les modifications de manière significative et vous permet également d'analyser le code plus facilement. Je ne peux pas penser à une raison technique.
la source
Cela permet de se protéger des erreurs causées par le déplacement d'éléments dans une longue liste.
Par exemple, supposons que nous ayons un code ressemblant à ceci.
Et c'est génial, car il montre la trilogie originale des sites Stack Exchange.
Mais il y a un problème avec ça. Vous voyez, le pied de page de ce site Web montre une défaillance du serveur avant le super utilisateur. Mieux vaut corriger cela avant que quiconque ne le remarque.
Après tout, déplacer des lignes ne pouvait pas être si difficile, n'est-ce pas?
Je sais, il n'y a pas de site Web appelé "Server FaultSuper User", mais notre compilateur prétend qu'il existe. Maintenant, le problème est que C a une fonctionnalité de concaténation de chaînes, qui vous permet d'écrire deux chaînes entre guillemets doubles et de les concaténer en utilisant rien (un problème similaire peut également se produire avec des entiers, comme
-
signe a plusieurs significations).Et si le tableau d'origine avait une virgule inutile à la fin? Eh bien, les lignes seraient déplacées, mais un tel bug ne serait pas arrivé. Il est facile de rater quelque chose d'aussi petit qu'une virgule. Si vous vous souvenez de mettre une virgule après chaque élément du tableau, un tel bogue ne peut tout simplement pas se produire. Vous ne voudriez pas perdre quatre heures à déboguer quelque chose, jusqu'à ce que vous trouviez que la virgule est la cause de vos problèmes .
la source
Comme beaucoup de choses, la virgule de fin dans un initialiseur de tableau est l'une des choses que C ++ hérite de C (et devra prendre en charge pour toujours). Une vue totalement différente de celles placées ici est mentionnée dans le livre "Deep C secrets" .
Après un exemple avec plus d'un "paradoxes de virgule":
nous lisons :
... pour moi, cela a plus de sens
la source
enum
cas est quelque peu intéressante, car c'est le cas où la virgule manquante poserait le moins d'ambiguïté. Étant donnéstruct foo arr[] = {{1,2,3,4,5}, {3,4,5,6,7}, }
; il y a deux significations sensées que la langue pourrait assigner: créer un tableau à deux éléments, ou créer un tableau à trois éléments où le dernier élément a des valeurs par défaut. Si C avait adopté l'interprétation ultérieure, je pourrais voir l'interdictionenum foo {moe, larry, curly, };
sur le principe qu'il ne devrait y avoir qu'une seule façon d'écrire la déclaration (sans la virgule), mais ...enum foo {moe,,larry,curly,};
comme sauter un nombre entremoe
etlarry
, il n'aurait généralement pas d'importance si la virgule de fin a été traitée ou ignorée. Le seul cas où cela pourrait être important serait si le dernier élément était la valeur maximale pour son type déclaré, et que ...Outre la facilité de génération et d'édition de code, si vous souhaitez implémenter un analyseur, ce type de grammaire est plus simple et plus facile à implémenter. C # suit cette règle à plusieurs endroits: il existe une liste d'éléments séparés par des virgules, comme des éléments dans une
enum
définition.la source
Cela facilite la génération de code car vous n'avez besoin d'ajouter qu'une seule ligne et n'avez pas besoin de traiter l'ajout de la dernière entrée comme s'il s'agissait d'un cas spécial. Cela est particulièrement vrai lors de l'utilisation de macros pour générer du code. Il y a une pression pour essayer d'éliminer le besoin de macros de la langue, mais une grande partie de la langue a évolué main dans la main avec des macros disponibles. La virgule supplémentaire permet de définir et d'utiliser des macros telles que les suivantes:
Usage:
C'est un exemple très simplifié, mais souvent ce modèle est utilisé par des macros pour définir des éléments tels que des cartes et des tableaux de répartition, de message, d'événement ou de traduction. Si une virgule n'était pas autorisée à la fin, nous aurions besoin d'un spécial:
et ce serait très difficile à utiliser.
la source
Ainsi, lorsque deux personnes ajoutent un nouvel élément dans une liste sur des branches distinctes, Git peut fusionner correctement les modifications, car Git fonctionne sur une base de ligne.
la source
Si vous utilisez un tableau sans longueur spécifiée, VC ++ 6.0 peut automatiquement identifier sa longueur, donc si vous utilisez "int a [] = {1,2,};" la longueur de a est 3, mais la dernière n'a pas ' t été initialisé, vous pouvez utiliser "cout <
la source