Непоследовательная диагностика gcc для инициализации строки

Я использую gcc 4.9.1/Mingw и компилирую код:

gcc test.c -otest.exe -std = c11 -pedantic-errors -Wall -Wextra

Этот код дает диагностику:

int main (void)
{
  char a[5] = {'h','e','l','l','o','\0'};
}

ошибка: избыточные элементы в инициализаторе массива char a[5]

Тем не менее, этот код не выдает предупреждение:

int main (void)
{
  char b[5] = "hello";
}

Я думал, что эти две формы были на 100% эквивалентны. Есть ли какая-либо причина или тонкость в стандарте C и т. Д., Почему последний не должен предупреждать?

Или это ошибка компилятора? Я знаю, что стандарт C допускает избыточные инициализаторы, в отличие от C++, поэтому формально я не верю, что gcc требуется для диагностики. Но я ожидаю, что компилятор будет выдавать предупреждения последовательно.

3 ответа

Решение

В то время как:

 char a[5] = {'h','e','l','l','o','\0'};

является недействительным.

(C11, 6.7.9p2) "Ни один инициализатор не должен пытаться предоставить значение для объекта, не содержащегося в инициализируемом объекте".

Это:

char b[5] = "hello";

явно разрешено C (выделено мной):

(C11, 6.7.9p14) "Массив символьного типа может быть инициализирован литералом строки символов или строковым литералом UTF-8, необязательно заключенным в фигурные скобки. Последовательные байты строкового литерала (включая завершающий нулевой символ, если есть место или если массив имеет неизвестный размер) инициализируйте элементы массива."

Но

 char b[5] = "hello!";

является недействительным.

Это странная причуда в стандарте C. Когда-то люди иногда использовали строки фиксированной длины, не заканчивающиеся нулем. (Одним из примеров были 14-символьные имена файлов в V7 Unix.) Поэтому, чтобы позволить этим старым программам продолжить компиляцию, законно инициализировать явно размерный файл. char массив со строковой константой, которая в конечном итоге соскребает '\0', как вы только что заметили.

Я согласен, что удивительно, что {'h','e','l','l','o','\0'} инициализатор предупрежден в то время как "hello" один не сделал. Но это две очень разные формы, и получается, что правила для них разные. Когда вы даете вашему массиву размер, и вы используете {} Форма, там должно быть место для всех ваших инициализаторов, точка. Но когда вы даете размер и используете "" форма, есть специальное исключение для этого случая и только для этого случая.

(Это также не разрешено в C++ для любой формы.)

В

char b[5] = "hello";  

\0 не добавляется к строке, потому что массив b имеет размер 5, Это действительно Компилятор думает об этом как

char b[5] = {'h','e','l','l','o'};

Вот b это массив chars. Но его нельзя использовать там, где следует предполагать строковый литерал. Например, вы не можете использовать b в printf с %s спецификатор или str семейная функция.

Другие вопросы по тегам