#c
Вопрос:
Является ли следующий допустимый/приемлемый код C для возврата строкового литерала?
char* level_str(level)
{
switch (level) {
case DEBUG: return "DEBUG";
case INFO: return "INFO";
case WARN: return "WARN";
case ERROR: return "ERROR";
default: return "UNKNOWN";
}
}
Или указатель на строковый литерал становится недопустимым/переопределяется в стеке после возврата функции? Если да, то есть только два допустимых способа сделать это: (1) удалить строку; или (2) записать в буфер, предоставленный вызываемым абонентом?
Комментарии:
1. Строковые литералы хранятся в
ready-only
разделе, а не в стеке. Таким образом, возврат указателя на него из функции безопасен.2. @chux-RestorateMonica не могли бы вы, пожалуйста, уточнить, что вы под этим подразумеваете? Означает ли это, что указатель/
char*
входит вrax
, и вызываемый абонент может использовать это, и поэтому строковые литералы в порядке?3. Ключ-это адрес строкового литерала (например
"hello world"
), который фиксирован и хорош для жизни программы. Таким образом, этот адрес не уничтожается при возврате функции (это просто литерал, доступный только для чтения, который является частью исполняемого файла). Таким образом, в отличие от локально объявленного массива, созданного в стеке функций, адрес строковых литералов может быть объявлен и возвращен из функции. Во время компиляции компилятор видит"hello world"
и просто делает его частью.rodata
раздела исполняемого файла. С achar array[12];
компилятор понятия не имеет, что это будет.4. @DavidC.Rankin «литерал только для чтения, который является частью исполняемого файла / / /» -это деталь реализации, хотя и распространенная. Ни код, ни среда не обязаны иметь раздел «только для чтения».
5.Ок, просто о любой другой компилятор на Земле, за исключением нестандартного соответствующие компиляторы, написанные в Microsoft, строковые литералы, перейдите в
.rodata
раздел исполняемого файла… но, знаю, что это реализация деталь, и есть очень популярный компилятор, который позволяет изменять строковые литералы вопреки тому, что большая часть остальной мир:)
С11 стандарт — 6.4.5(Р7)"If the program attempts to modify such an array, the behavior is undefined."
Ответ №1:
Может ли строковый литерал быть возвращен без malloc/буфера
ДА. Адрес строкового литерала можно перенастроить.
Код OP хорош, но лучше, const char* level_str(level)
поскольку данные const char *
указывают на то, что строковые литералы лучше оставить в покое, не пытаясь изменить.
Попытка изменить строковый литерал-это неопределенное поведение (UB). Может сработать, может не сработать, может произойти сбой и т. Д.
Ответ №2:
Да, строковый литерал ведет себя как указатель на массив char
, имеющий статическую длительность хранения и инициализированный заданными символами плюс завершающий нуль. Это означает, что это похоже на то, как если бы вы написали static char my_debug_string[] = { 'D', 'E', 'B', 'U', 'G', 0 };
и вернули указатель на my_debug_string
(за исключением того, что вы не должны изменять массив). В частности, срок службы этого массива составляет весь срок службы программы; он остается действительным после возврата из функции, в которой он появился.
Ссылка: Стандарт C17 6.4.5 (6-7).