Следующая программа прекрасно компилируется в C с предупреждениями, но не компилируется в C ++. Зачем? Какова причина?
#include <stdio.h>
int main(void)
{
char a[5]="Hello";
a[0]='y';
puts(a);
for(int i=0;i<5;i++)
printf("%c",a[i]);
return 0;
}
Предупреждение:
Warning:[Error] initializer-string for array of chars is too long [-fpermissive] enabled by default
Но если программа скомпилирована как программа C ++, то компилятор C ++ выдает следующую ошибку:
[Error] initializer-string for array of chars is too long [-fpermissive]
Я использую компилятор GCC 4.8.1.
Краткий ответ: потому что C и C ++ — это разные языки с разными правилами.
Длинный ответ: в обоих случаях причина в том, что массив слишком мал для строкового литерала. Литерал состоит из пяти видимых символов с нулевым терминатором на конце, поэтому общий размер равен 6.
В C вы можете инициализировать массив слишком длинной строкой; лишние символы просто игнорируются:
C99 6.7.8 / 14: Массив символьного типа может быть инициализирован литералом символьной строки, необязательно заключенным в фигурные скобки. Последовательные символы литерала символьной строки (включая завершающий нулевой символ, если есть место или если массив имеет неизвестный размер) инициализируют элементы массива.
Компилятор предупреждает, что строка слишком велика, поскольку почти наверняка указывает на ошибку; но он не может отклонить код, если вы не скажете, чтобы он воспринимал предупреждения как ошибки.
В C ++ инициализатору не разрешено быть больше, чем массив:
C ++ 11 8.5.2 / 2: Инициализаторов не должно быть больше, чем элементов массива.
поэтому для этого языка компилятор должен выдать ошибку.
В обоих языках, когда вы хотите, чтобы символьный массив соответствовал размеру инициализатора строкового литерала, вы можете не указывать размер, и компилятор сделает все правильно.
char a[] = "hello"; // size deduced to be 6
Проблема в нижней строке
char a[5]="Hello";
Нет места для хранения завершающего нуля.
По умолчанию, gcc
не выдает никаких ошибок для этого случая с -fpermissive
опция включена. Так что компилирует нормально в C
,
Согласно требованию от языковых стандартов,
C99
стандарт, глава 6.7.9, пункт 14,Массив символьного типа может быть инициализирован символьным строковым литералом или строковым литералом UTF-8, необязательно заключенным в фигурные скобки. Последовательные байты строкового литерала (включая завершающий нулевой символ, если есть место или массив имеет неизвестный размер) инициализируют элементы массива.
C++11
, глава 8.5.2, пункт 2Инициализаторов не должно быть больше, чем элементов массива.
Итак, код компилируется (с предупреждениями) с gcc
, выдает ошибку с g++
,
Допустимая строка в C и C ++ должна иметь \0
терминатор и в
char a[5]="Hello";
Там нет места для нулевого терминатора и не является допустимой строкой.
Так что это может не быть ошибкой в C, но вы обязательно столкнетесь с проблемами при использовании встроенных строковых функций, таких как strlen()
и семья.
Потому что «Привет» 6 char
с долго и г ++ без -fpermissive
не будет инициализировать 5 char
массив с ним, но GCC будет.