Существует огромная разница между:
const char s[] = "abcd";
и
const char* t = "abcd";
Первый из них декларирует s
быть объектом массива инициализируется из строки "ABCD". s
будет иметь адрес, отличный от адреса другого объекта в программе. Сама строка символов может быть артефактом времени компиляции; инициализация - это копия, поэтому символьная строка не должна присутствовать во время выполнения, если компилятор может найти другой способ выполнения инициализации (например, немедленную операцию хранилища).
Вторая декларация объявляет t
указателем на константу строки. Строковая константа теперь должна присутствовать во время выполнения, так как выражения, такие как t+1
, которые являются указателями внутри строки, действительны. Стандарт языка не гарантирует, что каждое вхождение строковых литералов в программе уникально и не гарантирует, что все вхождения объединены (хотя хорошие компиляторы будут пытаться сделать второй). Однако он гарантирует, что у них есть статическое время жизни ,
Следовательно, это неопределенное поведение, так как время жизни массива s
заканчивается, когда функция возвращает:
const char *gimme_a_string() {
const char s[] = "abcd";
return s;
}
Тем не менее, это хорошо:
const char *gimme_a_string() {
const char *s = "abcd";
return s;
}
также:
const char s[] = "abcd";
const char t[] = "abcd";
printf("%d\n", s == t);
гарантирует печать 0
, в то время как
const char* s = "abcd";
const char* t = "abcd";
printf("%d\n", s == t);
может печатать либо 0
или 1
, в зависимости от реализации. (Как написано, он почти наверняка напечатает 1
.Однако, если два заявления находятся в отдельных единицах компиляции и LTO не позволит, вероятно, печатать 0
)
Поскольку форма массива инициализируется копией неконстантная версия нормально:.
char s[] = "abcd";
s[3] = 'C';
Но версия указателя символов должна быть const
, чтобы избежать неопределенного поведения.
// Will produce a warning on most compilers with compile option -Wall or equivalent
char* s = "abcd";
// *** UNDEFINED BEHAVIOUR *** Can cause random program breakage
s[3] = 'C';
Технически неконстантная декларация s
является законным (поэтому компилятор только предупреждает), потому что это попытка изменить константу, которая является UB. Но вы всегда должны прислушиваться к предупреждениям компилятора; лучше думать об объявлении/инициализации как о неправильном, потому что это так.
Реализация должна решить, где хранить литералы –
Вы возвращаете указатель на локальный массив, который в любом случае является неопределенным поведением. – 5gon12eder
И FWIW, я не верю вам, когда вы заявляете, что литерал хранится в кадре стека. –