int a [] = {1,2,};Странная запятая разрешена.Любая конкретная причина? - PullRequest
323 голосов
/ 12 августа 2011

Возможно, я не с этой планеты, но мне кажется, что синтаксическая ошибка должна быть следующей:

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

Но это не так. Я был удивлен, когда этот код скомпилирован в Visual Studio, но я научился не доверять компилятору MSVC в том, что касается правил C ++, поэтому я проверил стандарт и он равен , разрешенным стандарт также. Вы можете увидеть 8.5.1 правила грамматики, если не верите мне.

enter image description here

Почему это разрешено? Это может быть глупый бесполезный вопрос, но я хочу, чтобы вы поняли, почему я спрашиваю. Если бы это был подслучайный случай общего правила грамматики, я бы понял - они решили не усложнять общую грамматику, просто запретив избыточную запятую в конце списка инициализатора. Но нет, дополнительная запятая явно разрешено. Например, нельзя использовать избыточную запятую в конце списка аргументов вызова функции (когда функция принимает ...), , что является нормальным .

Итак, опять же, есть ли какая-то особая причина, по которой эта избыточная запятая явно разрешена?

Ответы [ 19 ]

7 голосов
/ 13 августа 2011

Это проще для машин, т.е. разбора и генерации кода.Людям также легче, например, модификация, комментирование и визуальная элегантность через последовательность.

При условии C, вы бы написали следующее?

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

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

    return EXIT_SUCCESS
}

Нет.Не только потому, что последнее утверждение является ошибкой, но и потому, что оно несовместимо.Так почему же то же самое с коллекциями?Даже в тех языках, которые позволяют пропустить последние точки с запятой и запятые, сообществу это обычно не нравится.Сообщество Perl, например, не любит опускать точки с запятой, кроме однострочных.Они также применяются к запятым.

Не пропускайте запятые в многострочных коллекциях по той же причине, по которой вы не пропускаете точки с запятой для многострочных блоков кода.Я имею в виду, вы бы не сделали этого, даже если бы язык позволял это, верно?Правильно?

7 голосов
/ 12 августа 2011

Единственный язык, на котором он - на практике * - не разрешен, - это Javascript, и он вызывает неисчислимое количество проблем.Например, если вы скопировали и вставили строку из середины массива, вставили ее в конце и забыли удалить запятую, тогда ваш сайт будет полностью сломан для ваших посетителей IE.

* Теоретически эторазрешено, но Internet Explorer не соответствует стандарту и рассматривает его как ошибку

6 голосов
/ 12 августа 2011

Причина проста: простота добавления / удаления строк.

Представьте себе следующий код:

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

Теперь вы можете легко добавлять / удалять элементы в списке без необходимостииногда добавляйте / удаляйте завершающую запятую.

В отличие от других ответов, я на самом деле не думаю, что простота генерации списка является веской причиной: в конце концов, тривиально, чтобы код специально дляпоследняя (или первая) строка.Генераторы кода пишутся один раз и используются много раз.

6 голосов
/ 12 августа 2011

Позволяет каждой строке следовать одной и той же форме. Во-первых, это облегчает добавление новых строк и позволяет системе контроля версий осмысленно отслеживать изменения, а также позволяет легче анализировать код. Я не могу придумать техническую причину.

5 голосов
/ 10 мая 2014

Это позволяет защитить от ошибок, вызванных перемещением элементов в длинном списке.

Например, предположим, что у нас есть код, похожий на этот.

#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;
    }
}

И этоотлично, поскольку он показывает оригинальную трилогию сайтов Stack Exchange.

Stack Overflow
Super User
Server Fault

Но есть одна проблема с этим.Видите ли, нижний колонтитул на этом сайте показывает сбой сервера перед суперпользователем.Лучше исправить это, прежде чем кто-нибудь заметит.

#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;
    }
}

В конце концов, перемещение строк не может быть таким сложным, не так ли?

Stack Overflow
Server FaultSuper User

Я знаю, что веб-сайт под названием«Server FaultSuper User», но наш компилятор утверждает, что он существует.Теперь проблема в том, что в С есть функция конкатенации строк, которая позволяет вам писать две строки в двойных кавычках и конкатенировать их, не используя ничего (аналогичная проблема может возникнуть и с целыми числами, поскольку знак - имеет несколько значений).1017 * А что если исходный массив имеет бесполезную запятую в конце?Ну, линии будут перемещаться, но такой ошибки не было бы.Легко пропустить что-то такое маленькое, как запятая.Если вы не забыли ставить запятую после каждого элемента массива, такой ошибки просто не может быть.Вы не захотите тратить четыре часа на отладку чего-либо, пока не обнаружите, что причиной ваших проблем является запятая .

4 голосов
/ 30 июля 2015

Как и многие другие, конечная запятая в инициализаторе массива - это одна из вещей, наследуемых C ++ от C (и она должна будет поддерживаться всегда). Представление, полностью отличающееся от представленного здесь , упоминается в книге "Секреты глубокой С" .

Здесь после примера с более чем одним «парадоксом запятой»:

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? */
};

мы читаем:

... эту запятую после последней инициализатораэто не опечатка, но ошибка в синтаксисе, перенесенная с аборигена C .Его присутствие или отсутствие допускается, но не имеет значения не имеет значения .Обоснование, заявленное в обосновании ANSI, заключается в том, что оно облегчает автоматическую генерацию Си. Заявление было бы более правдоподобным, если бы в каждом списке с разделителями-запятыми были разрешены конечные запятые , например, в объявлениях enum или в нескольких деклараторах переменных в одном объявлении.Это не так.

... для меня это имеет больше смысла

2 голосов
/ 17 августа 2011

В дополнение к простоте генерации и редактирования кода, если вы хотите реализовать синтаксический анализатор, этот тип грамматики проще и проще в реализации. C # следует этому правилу в нескольких местах, где есть список разделенных запятыми элементов, например, элементов в определении enum.

1 голос
/ 23 апреля 2018

Это упрощает генерацию кода, так как вам нужно добавить только одну строку и не нужно обрабатывать добавление последней записи, как если бы это был особый случай.Это особенно верно при использовании макросов для генерации кода.Существует попытка устранить необходимость в макросах из языка, но многие языки развивались рука об руку с доступными макросами.Дополнительная запятая позволяет определять и использовать такие макросы, как следующие:

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

Использование:

LIST_BEGIN
   LIST_ENTRY(1)
   LIST_ENTRY(2)
LIST_END

Это очень упрощенный пример, но часто этот шаблон используется макросами дляопределение таких вещей, как карты и таблицы отправки, сообщения, события или перевода.Если запятая в конце не допускается, нам нужно специальное:

#define LIST_LAST_ENTRY(x) x

, и это будет очень неудобно для использования.

0 голосов
/ 18 августа 2011

Если вы используете массив без заданной длины, VC ++ 6.0 может автоматически определить его длину, поэтому если вы используете "int a [] = {1,2,};" длина a равна 3, но последняя один не был инициализирован, вы можете использовать "cout <

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...