Подтвердить что ты не робот

Выделение указателя на статические данные вне области видимости в C

Отказ от ответственности: этот вопрос строго академичен. Пример, который я собираюсь дать, - это, вероятно, плохой стиль.

Предположим, что в C я напишу подпрограмму этого вида:

char *foo(int x)
{
    static char bar[9];

    if(x == 0)
        strcpy(bar, "zero");
    else
        strcpy(bar, "not zero"),

    return bar;
}

Затем, в другом месте, я использую foo следующим образом:

printf("%i is %s\n", 5, foo(5));

Моя ментальная модель указателей и статических переменных предсказывает, что на практике вывод этого printf будет

5 не равно нулю

... но действительно ли это требуется стандартом C, или я нахожусь на территории носового демона?

Чтобы сделать вещи еще хуже, что-то вроде

strcpy(foo(5), "five");

Моя ментальная модель говорит, что это должно "работать", если оно явно не является незаконным, хотя оно несколько бессмысленно, поскольку оно не влияет на вывод foo. Но опять же, действительно ли это определено стандартом?

4b9b3361

Ответ 1

То, что вы написали, ОК; вас ждут носовые демоны. Даже пример strcpy() - "ОК", потому что вы не вытаскиваете за пределы массива. Это "ОК" в кавычках, потому что это не очень хорошая идея, но, как написано, нет доступа к границам памяти и, следовательно, никакого поведения undefined. Данные static в функции присутствуют на протяжении всего жизненного цикла программы, содержащие последнее значение, которое было написано на нем.

При попытке могут возникнуть проблемы:

printf("%i is %s but %i is %s\n", 5, foo(5), 0, foo(0));

Вы получите неправильный ответ для одного из двух чисел, но он не определен, что будет неправильным ответом.

Ответ 2

Ну, так как вам нужна цитата из стандарта:

Время жизни объекта - это часть выполнения программы в течение которого хранилище гарантировано зарезервировано для него.

Объект, идентификатор которого объявлен без спецификация класса хранения _Thread_local и либо с внешней, либо с внутренней связью или с типом хранилища класса static, имеет статическую продолжительность хранения. Его lifetime - это полное выполнение программы и ее сохраненное значение инициализируется только один раз, до запуска программы.

Ответ 3

При любом условии foo() возвращает указатель на статическую переменную, срок жизни которой постоянный (т.е. он живет, когда управление проходит через него в первый раз до конца программы). Это прекрасно.

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

Ответ 4

Я не вижу ничего плохого в этом коде.

Указатель, возвращаемый foo(), является допустимым указателем, и вам разрешено разыгрывать его.

Изменить: Под "ничего плохого" я ​​подразумеваю, что все синтаксически нормально, но я согласен с другими ответами, что этот код не подходит ни в каком значении этого слова по разным причинам. Это просто правильно в соответствии со стандартом C.

Ответ 5

В этом нет ничего плохого. Лучший стиль будет

 const char *foo(int x);

Тогда вы не можете вставлять в него, не отбрасывая const. Если вы действительно хотите сломать его, ничто не остановит вас.

если вы хотите сделать его повторным участником.

const char *foo(int x)
{
 return (x? "not zero" : "zero");
}