Непоследовательная диагностика 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
это массив char
s. Но его нельзя использовать там, где следует предполагать строковый литерал. Например, вы не можете использовать b
в printf
с %s
спецификатор или str
семейная функция.