Talvez eu não seja deste planeta, mas parece-me que o seguinte deve ser um erro de sintaxe:
int a[] = {1,2,}; //extra comma in the end
Mas isso não. Fiquei surpreso quando esse código foi compilado no Visual Studio, mas aprendi a não confiar no compilador MSVC no que diz respeito às regras do C ++, por isso verifiquei o padrão e ele também é permitido pelo padrão. Você pode ver 8.5.1 para as regras gramaticais se não acredita em mim.
Por que isso é permitido? Esta pode ser uma pergunta inútil estúpida, mas quero que você entenda por que estou perguntando. Se fosse um sub-caso de uma regra gramatical geral, eu entenderia - eles decidiram não tornar a gramática geral mais difícil apenas para impedir uma vírgula redundante no final de uma lista de inicializadores. Mas não, a vírgula adicional é explicitamente permitida. Por exemplo, não é permitido ter uma vírgula redundante no final de uma lista de argumentos de chamada de função (quando a função aceitar ...
), o que é normal .
Então, novamente, existe algum motivo específico para que essa vírgula redundante seja explicitamente permitida?
fonte
;
quando fica claro o próximo token é na verdade uma próxima declaração.for()
por exemplo), a adição dele lança um aviso do compilador.if (x = 1)
a gramática não é ambígua, mas é muito ambígua para os seres humanos e, portanto, lança um aviso.if
exemplo também não é ambíguo. Eu não acho que "ambíguo" significa o que você pensa que significa!Respostas:
Isso facilita a geração de código-fonte e também a gravação de código que pode ser facilmente estendido posteriormente. Considere o que é necessário para adicionar uma entrada extra a:
... você precisa adicionar a vírgula à linha existente e adicionar uma nova linha. Compare isso com o caso em que os três já tenham uma vírgula depois, onde você apenas precisará adicionar uma linha. Da mesma forma, se você deseja remover uma linha, pode fazê-lo sem se preocupar se é a última ou não, e pode reordenar as linhas sem mexer em vírgulas. Basicamente, significa que há uma uniformidade na forma como você trata as linhas.
Agora pense em gerar código. Algo como (pseudo-código):
Não precisa se preocupar se o item atual que você está escrevendo é o primeiro ou o último. Muito mais simples.
fonte
É útil se você fizer algo assim:
fonte
var a = [1, 2,];
assim como a maioria das outras linguagens que conheço ... ActionScript, Python, PHP.undefined
.Facilidade de uso para o desenvolvedor, eu acho.
Além disso, se por algum motivo você tiver uma ferramenta que gerou código para você; a ferramenta não precisa se preocupar se é o último item na inicialização ou não.
fonte
Sempre presumi que seja mais fácil acrescentar elementos extras:
simplesmente se torna:
Numa data posterior.
fonte
[1,2,3,]
está OK, mas{a:1, b:2, c:3,}
não está).Tudo o que todos estão dizendo sobre a facilidade de adicionar / remover / gerar linhas está correto, mas o lugar real em que essa sintaxe brilha é ao mesclar arquivos de origem. Imagine que você tem essa matriz:
E suponha que você tenha verificado esse código em um repositório.
Em seguida, seu amigo o edita, adicionando ao final:
E você o edita simultaneamente, adicionando ao início:
Semanticamente, esses tipos de operações (adicionando ao início e adicionando ao final) devem ser totalmente mesclados e o software de controle de versão (espero que o git) seja capaz de emergir automaticamente. Infelizmente, esse não é o caso, porque sua versão não tem vírgula após o 9 e o do seu amigo. Considerando que, se a versão original tivesse o 9 à direita, eles teriam se alimentado.
Portanto, minha regra geral é: use a vírgula à direita se a lista abranger várias linhas, não a use se a lista estiver em uma única linha.
fonte
Vírgula à direita, acredito que seja permitida por motivos de compatibilidade com versões anteriores. Há muito código existente, principalmente gerado automaticamente, o que coloca uma vírgula à direita. Facilita a gravação de um loop sem condição especial no final. por exemplo
Não há realmente nenhuma vantagem para o programador.
PS Embora seja mais fácil gerar automaticamente o código dessa maneira, eu sempre tomei o cuidado de não colocar a vírgula à direita, os esforços são mínimos, a legibilidade é aprimorada e isso é mais importante. Você escreve o código uma vez e o lê muitas vezes.
fonte
int a = b + c +;
ouif(a && b &&);
será mais fácil copiar e colar qualquer coisa no final e mais fácil escrever geradores de código. Esse problema é trivial e subjetivo; nesses casos, é sempre bom fazer o que é melhor para o leitor de código.&&
operador, às vezes eu faço condicionais comoif (true \n && b1 \n && b2)
para poder adicionar e remover linhas conforme necessário.Uma das razões pelas quais isso é permitido, até onde eu sei, é que deve ser simples gerar código automaticamente; você não precisa de nenhum tratamento especial para o último elemento.
fonte
Facilita os geradores de código que distribuem matrizes ou enumerações.
Imagine:
Ou seja, não é necessário fazer tratamento especial do primeiro ou do último item para evitar cuspir a vírgula à direita.
Se o gerador de código for escrito em Python, por exemplo, é fácil evitar cuspir a vírgula final usando a
str.join()
função:fonte
Estou surpreso depois de todo esse tempo que ninguém citou o Annotated C ++ Reference Manual ( ARM ), ele diz o seguinte sobre [dcl.init] com ênfase na minha:
embora a gramática tenha evoluído desde ARM foi escrito, a origem permanece.
e podemos ir para a lógica C99 para ver por que isso foi permitido em C e ele diz:
fonte
Vejo um caso de uso que não foi mencionado em outras respostas, nossas Macros favoritas:
Adicionar macros para lidar com o último
,
seria uma grande dor. Com essa pequena alteração na sintaxe, isso é trivial de gerenciar. E isso é mais importante que o código gerado por máquina, porque geralmente é muito mais fácil fazê-lo na linguagem completa de Turing do que no pré-processador muito limitado.fonte
O único idioma em que - na prática * - não é permitido é o Javascript e causa uma quantidade incontável de problemas. Por exemplo, se você copiar e colar uma linha do meio da matriz, cole-a no final e se esqueça de remover a vírgula, seu site ficará totalmente quebrado para os visitantes do IE.
* Em teoria, é permitido, mas o Internet Explorer não segue o padrão e o trata como um erro
fonte
var x = [,,,]
é legal (exceto no IE <9, mas a especificação diz que é legal)É mais fácil para máquinas, ou seja, análise e geração de código. Também é mais fácil para os seres humanos, ou seja, modificação, comentários e elegância visual através da consistência.
Supondo C, você escreveria o seguinte?
Não. Não apenas porque a declaração final é um erro, mas também porque é inconsistente. Então, por que fazer o mesmo com as coleções? Mesmo em idiomas que permitem omitir os últimos pontos e vírgulas e vírgulas, a comunidade geralmente não gosta. A comunidade Perl, por exemplo, não parece omitir ponto-e-vírgula, excluindo linhas. Eles aplicam isso a vírgulas também.
Não omita vírgulas em coleções com várias linhas pelo mesmo motivo que não omite ponto e vírgula para blocos de código com várias linhas. Quero dizer, você não faria isso mesmo que a linguagem permitisse, certo? Direita?
fonte
O motivo é trivial: facilidade de adicionar / remover linhas.
Imagine o seguinte código:
Agora, você pode adicionar / remover itens facilmente à lista sem precisar adicionar / remover a vírgula à direita algumas vezes.
Ao contrário de outras respostas, eu realmente não acho que a facilidade de gerar a lista seja uma razão válida: afinal, é trivial que o código tenha um caso especial na última (ou primeira) linha. Os geradores de código são escritos uma vez e usados muitas vezes.
fonte
Ele permite que todas as linhas sigam a mesma forma. Primeiro, isso facilita a adição de novas linhas e um sistema de controle de versão rastreia a alteração de forma significativa, além de permitir a análise do código com mais facilidade. Não consigo pensar em uma razão técnica.
fonte
Isso permite proteger contra erros causados pela movimentação de elementos em uma longa lista.
Por exemplo, vamos assumir que temos um código parecido com este.
E é ótimo, pois mostra a trilogia original dos sites do Stack Exchange.
Mas há um problema com isso. Veja, o rodapé deste site mostra a falha do servidor antes do superusuário. Melhor consertar isso antes que alguém perceba.
Afinal, mover linhas ao redor não poderia ser tão difícil, poderia ser?
Eu sei, não existe um site chamado "Server FaultSuper User", mas nosso compilador afirma que ele existe. Agora, o problema é que C possui um recurso de concatenação de strings, que permite escrever duas strings com aspas duplas e concatená-las usando nada (um problema semelhante também pode acontecer com números inteiros, como
-
sinal tem vários significados).Agora, e se a matriz original tivesse uma vírgula inútil no final? Bem, as linhas seriam deslocadas, mas esse erro não teria acontecido. É fácil perder algo tão pequeno quanto uma vírgula. Se você se lembrar de colocar uma vírgula após cada elemento da matriz, esse erro simplesmente não poderá ocorrer. Você não gostaria de perder quatro horas depurando alguma coisa, até descobrir que a vírgula é a causa dos seus problemas .
fonte
Como muitas coisas, a vírgula à direita em um inicializador de matriz é uma das coisas que o C ++ herdou do C (e terá que suportar para sempre). Uma visão totalmente diferente das colocadas aqui é mencionada no livro "Deep C secrets" .
Nele, após um exemplo com mais de um "paradoxo de vírgula":
nós lemos :
... para mim isso faz mais sentido
fonte
enum
caso é um tanto interessante, pois é o caso em que a vírgula ausente representaria a menor ambiguidade. Dadostruct foo arr[] = {{1,2,3,4,5}, {3,4,5,6,7}, }
; existem dois significados sensatos que o idioma pode atribuir: criar uma matriz de dois elementos ou criar uma matriz de três elementos em que o último item tenha valores padrão. Se C tivesse adotado a interpretação posterior, eu pude ver proibindoenum foo {moe, larry, curly, };
o princípio de que deveria haver apenas uma maneira de escrever a declaração (sem a vírgula), mas ... #enum foo {moe,,larry,curly,};
como pular um número entremoe
elarry
, geralmente não importa se a vírgula à direita foi processada ou ignorada. O único caso em que isso poderia importar seria se o último item fosse o valor máximo para o seu tipo declarado, e que ... #Além da facilidade de geração e edição de código, se você deseja implementar um analisador, esse tipo de gramática é mais simples e fácil de implementar. O C # segue essa regra em vários locais em que há uma lista de itens separados por vírgula, como itens em uma
enum
definição.fonte
Isso facilita a geração de código, pois você só precisa adicionar uma linha e não precisa adicionar a última entrada como se fosse um caso especial. Isso é especialmente verdade ao usar macros para gerar código. Há um esforço para tentar eliminar a necessidade de macros do idioma, mas grande parte do idioma evoluiu de mãos dadas com as macros disponíveis. A vírgula extra permite que macros como as seguintes sejam definidas e usadas:
Uso:
Esse é um exemplo muito simplificado, mas geralmente esse padrão é usado por macros para definir itens como tabelas e mapas de despacho, mensagem, evento ou tradução. Se uma vírgula não fosse permitida no final, precisaríamos de um especial:
e isso seria muito difícil de usar.
fonte
Assim, quando duas pessoas adicionam um novo item em uma lista em ramificações separadas, o Git pode mesclar adequadamente as alterações, porque o Git funciona em uma linha.
fonte
Se você usar uma matriz sem comprimento especificado, o VC ++ 6.0 poderá identificar automaticamente seu comprimento; portanto, se você usar "int a [] = {1,2,};" o comprimento de a é 3, mas o último não tem ' não foi inicializado, você pode usar "cout <
fonte