Падение при возврате из функции const char*

Рейтинг: 4Ответов: 3Опубликовано: 05.07.2023

Имеется данный код

const char* get_msg(){
    const char str[] = "get_msg";
    return str;
}

#include <stdio.h>
int main(){
    printf("%s\n", get_msg());
}

При компиляции выдается

warning: function returns address of local variable [-Wreturn-local-addr]

и естественно при выполнении приложение крашится. Я понимаю почему это происходит, ведь строка была на стеке и он уничтожается после того как функция вернула значение.

Однако если функцию переписать так

const char* get_msg(){
    return "get_msg";
}

То нет ни варнингов ни падения. Меня интересует, как работает return "get_msg"; ? Получается эта строка находится на стеке? Или где? Ведь эта строка по логике должна "исчезать" после возврата функции.

Компилирую так: gcc main.c -o main

Ответы

▲ 4Принят

Строка "get_msg" храниться в программе как статические данные в отделе, защищённом от изменений.
Приблизительно так :

__Stroka1234 : "get_msg"

Стандарт говорит про это так :

Evaluating a string-literal results in a string literal object with static storage duration, initialized from the given characters as specified above. Whether all string-literals are distinct (that is, are stored in non overlapping objects) and whether successive evaluations of a string-literal yield the same or a different object is unspecified.
[Note 7 : The effect of attempting to modify a string-literal is undefined. — end note]

Вычисление строкового литерала приводит к созданию объекта строкового литерала со статической продолжительностью хранения, инициализированного из заданных символов, как указано выше. Не указано, являются ли все строковые литералы различными (то есть хранятся в неперекрывающихся объектах) и приводят ли последовательные вычисления строкового литерала к одному и тому же или к другому объекту.
[Примечание 7: Эффект от попытки изменить строковый литерал не определен. — заключительная нота]

Строка const char str[] = "get_msg"; как копия храниться в стеке. И после окончания работы функции обращение к строке приведёт к неопределённому поведению.

А если вы возвращаете адрес return "get_msg"; статической безымянной строки, то можете к ней обращаться всегда, только не изменять.

▲ 5

Здесь

const char str[] = "get_msg";

выделяется место для массива str на стеке, он заполняется строкой "get_msg" (строковый литерал копируется в массив в стеке). Потом функция возвращает адрес этого массива.

Тут же

return "get_msg";

возвращается адрес места в некоторой памяти, где хранятся строковые литералы (упрощенно, это место зависит от компилятора, операционки и т.д.). Т.е. этот адрес будет указывать на действительное место в памяти, в то время как в предыдущем return возвращается указатель на место в стеке.

▲ 1

Код

const char* get_msg(){
    return "get_msg";
}

эквивалентен коду

const char* get_msg(){
    static const char str[] = "get_msg";
    return str;
}