LINUX.ORG.RU

Срок жизни строкового литерала в C

 


0

3

Я делаю пространство имён — множество пар «строка - объект». В функции инициализации я создаю статический массив, а потом копирую всю эту память в динамический, вот этак:

init() {
  name_t names[2] = {
    {"name1", obj1},
    {"name2", obj2}
  }
  <...>
  memcpy(global_namespace.names, names, size);
}

Здесь global_namespace — это структура, в которой есть указатель на имена.

А вопрос мой вот в чём: как долго будут жить строковые константы? Потом ведь нужно будет к ним обращаться — не хотелось бы, чтобы затёрлись. Мне думается, что компилятор положит их в неизменяемую память, и на протяжении всей жизни программы можно будет обращаться. Но они объявлены внутри функции и, вроде как, локальные объекты — это не повлияет?


Ответ на: комментарий от dyonya
 name_t names[2] = {
    {"name1", obj1},
    {"name2", obj2}
  }

Это на стеке, и не будет существовать после выхода из init()

Но `memcpy(global_namespace.names, names, size);’ копирует то, что по указателю на src(names) и размером size в выделенню заранее память и доспупную по указателю dst(global_namespace.names);

Что там у тебя за size, и что там за global_namespace.names - это телепаты фсё…

her_s_gory
()
Ответ на: комментарий от her_s_gory

Так-то оно так, всё понимаю. Но момент неявный: копирую я строковую константу, объявленную внутри функции. И доступ к ней есть, строка не затирается. Хочу убедиться, что так и будет дальше.

dyonya
() автор топика
Ответ на: комментарий от her_s_gory

Человек задал простой вопрос - каков срок жизни строкового литерала и структуры со строковым литералом в приведённом коде.

Вместо ответа на вопрос ты начал писать, что автор - гавно, и какой ты молодец, раз знаешь понятия стек/куча/время жизни. Кстати, раз уж на то пошло - в стандарте Си нет понятий стек и куча, а есть automatic storage duration и allocated object.

mxfm ★★
()

см. стандарт 6.2.4 storage duration of objects

срок жизни строкового литерала в Си, если он объявлен вне функции - время работы программы, так как у него static storage duration

но в приведённом примере строка является частью структуры, объект которой создаётся внутри функции. Срок жизни такой структуры - выход из ближайшего блока } (в данном случае - выход из функции)

mxfm ★★
()
Ответ на: комментарий от mxfm

ну да, настоящие профи читают не стандарт, а форум наталия-аппмарт-ру

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

her_s_gory
()
Ответ на: комментарий от mxfm

но в приведённом примере строка является частью структуры, объект которой создаётся внутри функции. Срок жизни такой структуры - выход из ближайшего блока } (в данном случае - выход из функции)

Значит всё-таки учебник по первому занятию «C за неделю» вслух прочитать надо было. Ну ок.

her_s_gory
()
Ответ на: комментарий от mxfm

Спасибо за содержательный ответ!

Только вот, как ни крути, по выходе из {} строка всё равно доступна. Так компилирует gcc. Это противоречит стандарту? Нужно ли, от греха подальше, избегать такого паттерна программирования?

dyonya
() автор топика

Их откуда-то надо занести в работающую программу. Кроме самого бинарника, который живёт всё время жизни программы, способа это сделать нет. Даже если они там копируются, и эти копии удаляются, это уже вопросы рантайма, сам литерал всегда есть в исходном виде.

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

neumond
()
Ответ на: комментарий от alysnix

более того. компиляторы, когда видят строковую константу, смотрят - если ли она уже в пуле констант. если есть, ее не вводят в пул, а берут адрес от уже имеющейся. то есть дубликатов строковых констант там не будет.

alysnix ★★★
()
Ответ на: комментарий от neumond

Обычно в наколеночных программах задаётся строковая константа заданной длины и по указателю используется как переменная. Но это говнокод.

Shadow ★★★★★
()
Ответ на: комментарий от dyonya

Это противоречит стандарту?

Нет. Стандарт не гарантирует, что обязательно затрёт что-то при выходе из скопа. В общем случае если память на стеке доступна при схлопывании стека - то это случайность. Может перезатереться, может не перезатереться - короче UB.

Эксплуатировать UB - можешь, конечно, если ты рисковый, но зачем, если можно делать по учебнику, и не искать магические стечения обстоятельств.

her_s_gory
()
Последнее исправление: her_s_gory (всего исправлений: 1)

C23, 6.4.5 String Literals:

Semantics
...
 The multibyte character sequence is then used
to initialize an array of static storage duration and length just sufficient to contain the sequence.

Про static storage duration в 6.2.4:

An object whose identifier is declared without the storage-class specifier thread_local, and either
with external or internal linkage or with the storage-class specifier static, has static storage duration.
Its lifetime is the entire execution of the program and its stored value is initialized only once, prior
to program startup.

Короче, лайфтайм строкового литерала – это вся программа, инициализирован он заранее. Только изменять это UB, об этом в том же разделе про строковые литералы написано.

a1ba ★★
()
Последнее исправление: a1ba (всего исправлений: 1)
Ответ на: комментарий от her_s_gory

А стандарт - это слишком для них сложно.

стандарт, стандарт, стандарт..

у сишек плюсишек какая-то ошибочная фиксация на стандарте

программисты не должны читать никакой стандарт.

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

например программисты не читают стандарт SQL. его чтение требует серьезных усилий и опыта именно в чтении SQL стандарта, оно бесполезно программисту. для программиста есть книги (правда немного) именно по SQL от серьезных специалистов в том числе имеющих отношение к стандарту, есть документация конкретной СУБД.

например жависты не читают JLS чтобы писать программы на жаве, они не читают JLS даже чтобы понять JMM (для программиста этот текст про JMM бесполезен, главу сложно понять без специальной подготовки именно в этой теме, для этого, как говорят специалисты в этой теме, нужно несколько книг прочесть предварительно). для этого есть другие материалы: официальная документация, книги от разработчика языка касаемо нужных тем, сторонние книги - этого достаточно, там есть то что нужно

если программист вынужден читать стандарт, то с этой технологией что-то не то

asdpm
()

Любой строковый литерал - это указатель на место в статической области памяти, предынициализированной компилятором, в которое компилятор этот самый литерал положил. Так что живёт он в течение всего времени работы программы. Нубов, которые втирают что-то про стек и области видимости, не слушай.

И замени char* на char const* т.к. литерал нельзя модифицировать. По-хорошему с char* вообще должно ошибку компиляции, но компиляторы эту конструкцию поддерживают для совместимости с древним кодом из 70-х-80-х, где const не было.

И ещё важная оговорка на всякий случай. Если ты напишешь так:

char st[] = "qwe";
(то есть, в явном виде задашь массив вместо указателя) то st будет уже не указателем на литерал, а обычной переменной, в которую записали эту строку, и живёт она как обычная переменная.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от dyonya

Нужно ли, от греха подальше, избегать такого паттерна

Нужно избегать засорения словаря ненужными умными словами.

struct {
  char  *name;
  obj_t  obj;
}

тогда name инициализируются значением литералов "name1", "names", обозначающим объекты со статическим временем жизни (char[6] приводится к char*, указывающему на первый элемент массива, обозначаемого литералом).

In translation phase 7 (5.2.1.2), a byte or code of value zero is appended to each multibyte character sequence that results from a string literal or literals.74) The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3467.pdf#subsection.0.6.4.6

сам проинциализированный names – автоматический, а names[0].name[0] сразу после инициализации обозначает статический объект.

vM ★★
()