Может ли статическая функция c вернуть локальный массив символов?
В библиотеке zflog я видел этот код
static char* lvl_char(const int lvl)
{
switch (lvl)
{
case ZF_LOG_VERBOSE:
return "VERBOSE\0";
case ZF_LOG_DEBUG:
return "DEBUG\0";
case ZF_LOG_INFO:
return "INFO\0";
case ZF_LOG_WARN:
return "WARN\0";
case ZF_LOG_ERROR:
return "ERROR\0";
case ZF_LOG_FATAL:
return "FATAL\0";
default:
ASSERT_UNREACHABLE("Bad log level");
return "?\0";
}
}
что показалось мне странным Можем ли мы действительно вернуть локальную строку c из статических функций?
4 ответа
Вы не правы, возвращаемый указатель не указывает на локальный char array
, но к string literal
, то есть static
для процесса.
Из с-стандарта
6.4.5 Строковые литералы
Sematics
На этапе 7 преобразования байт или код нулевого значения добавляется к каждой многобайтовой символьной последовательности, которая получается из строкового литерала или литералов.78) Затем многобайтовая символьная последовательность используется для инициализации массива статической длительности и длины статического хранения, достаточных только для содержать последовательность.[...]
Эмефазис мой
Связь функции (здесь статическая) не имеет значения вообще. Также не возвращается "строка"; вместо этого возвращается указатель на символ. Вполне законно возвращать указатели на первый символ строковых литералов - строковые литералы гарантированно существуют на протяжении всей программы. C11 6.4.5p6 утверждает, что строковые литералы в том виде, в котором они здесь используются, используются для инициализации *"[анонимного] массива статической длительности и длины, достаточных для хранения последовательности". Статическая продолжительность хранения означает, что его "время жизни - это полное выполнение программы, а его сохраненное значение инициализируется только один раз, до запуска программы". ( C11 6.2.4p3).
То, что выглядит странно, это \0
в конце строковых литералов, так как литеральные строки всегда заканчиваются 0, так что по существу "VERBOSE\0"
будет просто завершено с 2 нулевыми байтами вместо обычного; strlen
для этой строки будет возвращаться 7
так же, как это вернулось бы для "VERBOSE"
, и так далее.
Может ли статическая функция c вернуть локальный массив символов?
TL; DR независимо от static
или же extern
Функции не должны возвращать локальный массив, потому что он не может использоваться осмысленно.
Теперь, чтобы проработать вопрос в руке,
.... статические функции?
У вас там было static
связан со связью для "функции", а не с возвращаемым значением или типом.
Вот, static
спецификатор хранения означает, что функция имеет внутреннюю связь, т. е. доступна только из модуля перевода.
связанные с C11
Глава §6.2.2
Если объявление идентификатора области файла для объекта или функции содержит спецификатор класса хранения
static
, идентификатор имеет внутреннюю связь.
ОТОХ, return
заявления как
return "FATAL\0";
return "DEBUG\0"; ///and so on
фактически возвращает указатель на первый элемент строкового литерала, который по определению имеет статическую длительность хранения Примечание 1, поэтому возвращаемое значение
- соответствует типу возврата,
char *
Заметка 2 - действителен после возврата заявления. Заметка 3
Примечание 1:
квотирование C11
глава §6.4.5/ P6
На этапе 7 перевода байт или код нулевого значения добавляются к каждой многобайтовой последовательности символов, которая является результатом строкового литерала или литералов. 78) Последовательность многобайтовых символов затем используется для инициализации массива статической длительности и длины, достаточных для хранения последовательности. Для символьных строковых литералов элементы массива имеют тип
char
и инициализируются отдельными байтами многобайтовой последовательности символов.
Заметка 2:
Цитирование главы §6.3.2.1/P3,
За исключением случаев, когда это операнд
sizeof
оператор,_Alignof
оператор, или унарный&
оператор или строковый литерал, используемый для инициализации массива, выражение с типом '' массив типа '' преобразуется в выражение с типом '' указатель на тип '', которое указывает на начальный элемент объекта массива и это не lvalue.
Заметка 3:
Цитирование главы §6.2.4/P3
Объект, идентификатор которого объявлен без спецификатора класса хранения _Thread_local, а также с внешней или внутренней связью или со спецификатором класса хранения
static
, имеет статическую продолжительность хранения. Его время жизни - это полное выполнение программы, и его сохраненное значение инициализируется только один раз, до запуска программы.
- Может ли статическая функция c вернуть локальный массив символов? Нет, это ведет к неопределенному поведению.
- Ваш код возвращает локальный массив символов? Нет. Возвращает указатель на строковый литерал, который находится в постоянной памяти. Эта память не локальна.
- Можете ли вы вернуть указатель на строковый литерал из любой функции? Да.
- Есть ли разница между обычными функциями внутренней связи
static
те здесь? Нет.