int a [] = {1,2,}; Se permite una coma rara. Alguna razón en particular?


Tal vez no soy de este planeta, pero me parece que lo siguiente debería ser un error de sintaxis:

int a[] = {1,2,}; //extra comma in the end

Pero no lo es. Me sorprendió cuando compilé este código en Visual Studio, pero he aprendido a no confiar en el compilador MSVC en lo que respecta a las reglas de C++, así que revisé el estándar y es permitido por el estándar también. Puedes ver 8.5.1 para las reglas gramaticales si no me crees.

introduzca la descripción de la imagen aquí

¿Por qué se permite esto? Esto puede ser un estúpida pregunta inútil pero quiero que entiendas por qué estoy preguntando. Si fuera un sub-caso de una regla de gramática general, lo entendería-decidieron no hacer la gramática general más difícil solo para rechazar una coma redundante al final de una lista inicializador. Pero no, la coma adicional es explícitamente permitido. Por ejemplo, no se permite tener una coma redundante al final de una lista de argumentos de llamada a función (cuando la función toma ...), que es normal.

Así que, de nuevo, ¿hay alguna razón en particular esta coma redundante es explícitamente ¿permitido?

Author: Columbo, 2011-08-12

19 answers

Hace que sea más fácil generar código fuente, y también escribir código que se puede extender fácilmente en una fecha posterior. Considere lo que se requiere para agregar una entrada adicional a:

int a[] = {
   1,
   2,
   3
};

... usted tiene que agregar la coma a la línea existente y añadir una nueva línea. Compare eso con el caso donde los tres ya tienen una coma después de él, donde solo tiene que agregar una línea. Del mismo modo si desea eliminar una línea puede hacerlo sin preocuparse de si es la última línea o no, y usted puede reordenar líneas sin juguetear con comas. Básicamente significa que hay una uniformidad en la forma de tratar las líneas.

Ahora piensa en generar código. Algo así como (pseudo-código):

output("int a[] = {");
for (int i = 0; i < items.length; i++) {
    output("%s, ", items[i]);
}
output("};");

No hay necesidad de preocuparse por si el elemento actual que está escribiendo es el primero o el último. Mucho más simple.

 413
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-13 15:23:01

Es útil si haces algo como esto:

int a[] = {
  1,
  2,
  3, //You can delete this line and it's still valid
};
 122
Author: Skilldrick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-12 16:39:52

Facilidad de uso para el desarrollador, creo.

int a[] = {
            1,
            2,
            2,
            2,
            2,
            2, /*line I could comment out easily without having to remove the previous comma*/
          }

Además, si por alguna razón tenía una herramienta que generaba código para usted; la herramienta no tiene que preocuparse de si es el último elemento en la inicialización o no.

 37
Author: vcsjones,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-12 16:40:57

Siempre he asumido que hace que sea más fácil agregar elementos adicionales:

int a[] = {
            5,
            6,
          };

Simplemente se convierte en:

int a[] = { 
            5,
            6,
            7,
          };

En una fecha posterior.

 32
Author: Oliver Charlesworth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-12 16:39:34

Todo lo que todos dicen sobre la facilidad de agregar/eliminar/generar líneas es correcto, pero el lugar real donde brilla esta sintaxis es cuando se fusionan los archivos fuente. Imagina que tienes esta matriz:

int ints[] = {
    3,
    9
};

Y supongamos que ha comprobado este código en un repositorio.

Luego tu amigo lo edita, agregando al final:

int ints[] = {
    3,
    9,
    12
};

Y lo editas simultáneamente, añadiendo al principio:

int ints[] = {
    1,
    3,
    9
};

Semánticamente este tipo de operaciones (añadiendo al principio, agregar al final) debe ser completamente seguro para fusionar y su software de control de versiones (con suerte git) debe ser capaz de fusionar automáticamente. Lamentablemente, este no es el caso porque tu versión no tiene coma después del 9 y la de tu amigo sí. Mientras que, si la versión original había detrás de la 9, habrían automerged.

Entonces, mi regla general es: use la coma final si la lista abarca varias líneas, no la use si la lista está en una sola línea.

 17
Author: amoss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-16 17:41:54

Creo que la coma final está permitida por razones de compatibilidad con versiones anteriores. Hay una gran cantidad de código existente, principalmente auto-generado, que pone una coma final. Hace que sea más fácil escribir un bucle sin condiciones especiales al final. por ejemplo,

for_each(my_inits.begin(), my_inits.end(),
[](const std::string& value) { std::cout << value << ",\n"; });

Realmente no hay ninguna ventaja para el programador.

P.d. Aunque es más fácil autogenerar el código de esta manera, en realidad siempre tuve cuidado de no poner la coma final, los esfuerzos son mínimos, se mejora la legibilidad, y eso es más importante. Escribes código una vez, lo lees muchas veces.

 15
Author: Gene Bushuyev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-12 16:58:37

Una de las razones por las que esto está permitido hasta donde yo sé es que debería ser simple generar código automáticamente; no necesitas ningún manejo especial para el último elemento.

 12
Author: Fredrik Pihl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-12 16:41:40

Hace que los generadores de código que escupen matrices o enumeraciones sean más fáciles.

Imagine:

std::cout << "enum Items {\n";
for(Items::iterator i(items.begin()), j(items.end); i != j; ++i)
    std::cout << *i << ",\n";
std::cout << "};\n";

Es decir, no hay necesidad de hacer un manejo especial del primer o último elemento para evitar escupir la coma final.

Si el generador de código está escrito en Python, por ejemplo, es fácil evitar escupir la coma final usando la función str.join():

print("enum Items {")
print(",\n".join(items))
print("}")
 11
Author: Maxim Egorushkin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-12 16:46:58

El único lenguaje donde - en la práctica* - no está permitido es Javascript, y causa una cantidad innumerable de problemas. Por ejemplo, si copia y pega una línea desde el centro de la matriz, pégala al final y olvidó eliminar la coma, entonces su sitio estará totalmente roto para sus visitantes de IE.

* En teoría está permitido, pero Internet Explorer no sigue el estándar y lo trata como un error

 7
Author: Andreas Bonini,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-12 18:37:15

La razón es trivial: facilidad para agregar/eliminar líneas.

Imagine el siguiente código:

int a[] = {
   1,
   2,
   //3, // - not needed any more
};

Ahora, puede agregar/eliminar fácilmente elementos a la lista sin tener que agregar/eliminar la coma final a veces.

En contraste con otras respuestas, realmente no creo que la facilidad de generar la lista sea una razón válida: después de todo, es trivial que el código ponga un caso especial en la última (o primera) línea. Los generadores de código se escriben una vez y se usan muchas veces.

 6
Author: Vlad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-12 16:40:47

Es más fácil para las máquinas, es decir, analizar y generar código. También es más fácil para los humanos, es decir, modificación, comentarios y elegancia visual a través de la consistencia.

Asumiendo C, ¿escribirías lo siguiente?

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    puts("Line 1");
    puts("Line 2");
    puts("Line 3");

    return EXIT_SUCCESS
}

No. No solo porque la declaración final es un error, sino también porque es inconsistente. Entonces, ¿por qué hacer lo mismo con las colecciones? Incluso en los idiomas que permiten omitir los últimos puntos y comas, a la comunidad generalmente no le gusta. La comunidad Perl, por ejemplo, no parece que le guste omitir punto y coma, barras de una sola línea. También lo aplican a las comas.

No omita comas en colecciones multilínea por la misma razón que no omite punto y coma para bloques de código multilínea. Quiero decir, no lo harías aunque el lenguaje lo permitiera, ¿verdad? ¿Verdad?

 6
Author: Louis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-12 23:17:11

Me sorprende que después de todo este tiempo nadie haya citado el Manual de Referencia de C++ anotado de (ARM ), dice lo siguiente sobre [dcl.init] con énfasis mío:

Claramente hay demasiadas notaciones para inicializaciones, pero cada una parece servir bien a un estilo particular de uso. La notación ={initializer_list,opt} fue heredada de C y sirve bien para la inicialización de estructuras de datos y matrices. [...]

Aunque la gramática ha evolucionado desde que ARM fue escrito, el origen permanece.

Y podemos ir a la justificación C99 para ver por qué esto fue permitido en C y dice:

K & R permite una coma final en un inicializador al final de un inicializador-lista. El Estándar ha mantenido esta sintaxis, ya que proporciona flexibilidad para agregar o eliminar miembros de un inicializador lista, y simplifica la generación de la máquina de tales lista.

 6
Author: Shafik Yaghmour,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-19 11:59:16

Permite que cada línea siga la misma forma. En primer lugar, esto hace que sea más fácil agregar nuevas filas y tener un sistema de control de versiones para rastrear el cambio de manera significativa y también le permite analizar el código más fácilmente. No se me ocurre una razón técnica.

 5
Author: Mark B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-12 16:40:52

Esto se permite para proteger de errores causados por mover elementos en una larga lista.

Por ejemplo, supongamos que tenemos un código con este aspecto.

#include <iostream>
#include <string>
#include <cstddef>
#define ARRAY_SIZE(array) (sizeof(array) / sizeof *(array))
int main() {
    std::string messages[] = {
        "Stack Overflow",
        "Super User",
        "Server Fault"
    };
    size_t i;
    for (i = 0; i < ARRAY_SIZE(messages); i++) {
        std::cout << messages[i] << std::endl;
    }
}

Y es genial, ya que muestra la trilogía original de sitios de Stack Exchange.

Stack Overflow
Super User
Server Fault

Pero hay un problema con ello. Verá, el pie de página en este sitio web muestra un error del Servidor antes de Superusuario. Mejor arregla eso antes de que alguien se dé cuenta.

#include <iostream>
#include <string>
#include <cstddef>
#define ARRAY_SIZE(array) (sizeof(array) / sizeof *(array))
int main() {
    std::string messages[] = {
        "Stack Overflow",
        "Server Fault"
        "Super User",
    };
    size_t i;
    for (i = 0; i < ARRAY_SIZE(messages); i++) {
        std::cout << messages[i] << std::endl;
    }
}

Después de todo, mover líneas no podría ser tan difícil, ¿podría ser?

Stack Overflow
Server FaultSuper User

Lo sé, no hay un sitio web llamado "Server FaultSuper User", pero nuestro compilador afirma que existe. Ahora, el problema es que C tiene una función de concatenación de cadenas, que le permite escribir dos cadenas entre comillas dobles y concatenarlas sin usar nada (un problema similar también puede ocurrir con enteros, ya que el signo - tiene múltiples significados).

¿Y si la matriz original tuviera una coma inútil al final? Bueno, las líneas se moverían, pero tal insecto no tendría suceder. Es fácil perderse algo tan pequeño como una coma. Si recuerda poner una coma después de cada elemento del array, tal error no puede ocurrir. Usted no querría perder cuatro horas depurando algo, hasta que encuentre que la coma es la causa de sus problemas.

 5
Author: Konrad Borowski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-13 18:54:23

Veo un caso de uso que no se mencionó en otras respuestas, nuestras Macros favoritas:

int a [] = {
#ifdef A
    1, //this can be last if B and C is undefined
#endif
#ifdef B
    2,
#endif
#ifdef C
    3,
#endif
};

Agregar macros para manejar last , sería un gran dolor. Con este pequeño cambio en la sintaxis esto es trivial de manejar. Y esto es más importante que el código generado por la máquina porque generalmente es mucho más fácil de hacerlo en la lengua completa de Turing que el preprocesor muy limitado.

 5
Author: Yankes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-20 20:55:41

Como muchas cosas, la coma final en un inicializador de matriz es una de las cosas que C++ heredó de C (y tendrá que soportar para siempre). Una visión totalmente diferente de las que se encuentran aquí se menciona en el libro "Deep C secrets".

Allí después de un ejemplo con más de una "paradojas de coma":

char *available_resources[] = {
"color monitor"           ,
"big disk"                ,
"Cray"                      /* whoa! no comma! */
"on-line drawing routines",
"mouse"                   ,
"keyboard"                ,
"power cables"            , /* and what's this extra comma? */
};

Leemos:

...esa coma final después del inicializador final no es un error tipográfico, sino un blip en la sintaxis arrastrada desde aboriginal C . Su presencia o ausencia está permitida pero no tiene ninguna significación. La justificación alegada en la ANSI C es que facilita la generación automatizada de C. La afirmación sería más creíble si se permitieran comas finales en cada lista con clasificación sepa, como en las declaraciones de enumeración, o declaradores de múltiples variables en una sola declaración. No lo son.

... para mí, esto tiene más sentido

 4
Author: Nikos Athanasiou,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-30 14:16:59

Además de la facilidad de generación y edición de código, si desea implementar un analizador sintáctico, este tipo de gramática es más simple y fácil de implementar. C# sigue esta regla en varios lugares donde hay una lista de elementos separados por comas, como elementos en una definición enum.

 2
Author: Iravanchi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-16 21:03:01

Facilita la generación de código, ya que solo necesita agregar una línea y no necesita tratar la adición de la última entrada como si fuera un caso especial. Esto es especialmente cierto cuando se utilizan macros para generar código. Hay un impulso para tratar de eliminar la necesidad de macros del lenguaje, pero una gran parte del lenguaje evolucionó de la mano con las macros disponibles. La coma extra permite definir y usar macros como las siguientes:

#define LIST_BEGIN int a[] = {
#define LIST_ENTRY(x) x,
#define LIST_END };

Uso:

LIST_BEGIN
   LIST_ENTRY(1)
   LIST_ENTRY(2)
LIST_END

Eso es un muy ejemplo simplificado, pero a menudo este patrón es utilizado por macros para definir cosas como mapas y tablas de despacho, mensaje, evento o traducción. Si no se permitiera una coma al final, necesitaríamos un especial:

#define LIST_LAST_ENTRY(x) x

Y eso sería muy incómodo de usar.

 1
Author: Scott Langham,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-23 12:15:49

Si usa una matriz sin longitud especificada, VC++6.0 puede identificar automáticamente su longitud, por lo que si usa "int a [] = {1,2,};" la longitud de a es 3, pero la última no se ha inicializado, puede usar " cout

 -4
Author: zhi_jian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-18 01:10:29