• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Помогите разобраться с String vs char[]

rst

Member
Секции данных делятся на инициализированные т е те, где записаны константы программы те переменные которым вы присвоили значения
Упорно продолжаете нести чушь.
Константы vs переменные - совершенно разные сущности и помещаются компоновщиком в разные секции. Даже на ПК. Где секция констант закрывается после этого от доступа на запись (хоть и находится в ОЗУ). А в МК тем более - секция констант (как и секция кода) помещается во флешь (если таковая имеется). Секции же переменных (и секция инициализированных переменных и секция обнуляемых переменных) - помещаются в ОЗУ. Поэтому - константы по определению не могут находиться в одной секции с переменными.
 

rst

Member
Это переменые, которые Вы выделяете вне функций т е они глобальные
а также константы внутри функций
Внутри функций также можно создать переменные, которые будут находиться в секции данных (инициализированных или нет), а не на стеке. С помощью ключевого слова static.
А также создать константы, которые будут находиться не в секции констант, а на стеке/в_регистрах (как локальные автоматические переменные) - не указав при их описании слово static. Так что - не все константы находятся в секции констант.
 

nikolz

Well-known member
Внутри функций также можно создать переменные, которые будут находиться в секции данных (инициализированных или нет), а не на стеке. С помощью ключевого слова static.
А также создать константы, которые будут находиться не в секции констант, а на стеке/в_регистрах (как локальные автоматические переменные) - не указав при их описании слово static. Так что - не все константы находятся в секции констант.
Было бы больше толку , если вы вместо ярлыков на чужие высказывания, писали бы свои рассуждения по теме.
-----------------------------------
Я попытался объяснить человеку упрощенно.
Если есть у него желание, то прочтет в надлежащем учебнике.
-----------------
Не возражаю, если вы изложите более точно содержимое учебников.
Главное чтобы чел понял.
 

nikolz

Well-known member
здесь можно почитать про структуру exe файла
 

nikolz

Well-known member
Это все понятно, теорию я тоже читал. Дьявол кроется в деталях. Меня интересует вот такие два случая? Будет ли экономия heap в первом примере по сравнению со вторым?

Код:
foo(const uint8_t var)
{
  //brilliant code here
}
Код:
foo(uint8_t var)
{
  //brilliant code here
}

Знаю и понимаю. Но вот этот набор русских слов никак не проливает свет НОВИЧКУ на то, что такое volatile, а только ещё больше вгоняет его в ступор и безнадегу.

Уже даже не 10-й раз сталкиваюсь с адскими объяснением в советских учебниках. Открываю английский учебник и все понятно с первого раза, а английский у меня так себе. Как так?
почему Вы просто не соберете ваши примеры и не определите сколько памяти из кучи они скушают?
 

nikolz

Well-known member
Типичная схема памяти запущенного процесса

1. Текстовый сегмент:
Текстовый сегмент, также известный как сегмент кода или просто как текст, является одним из разделов программы в объектном файле или в памяти, которая содержит исполняемые инструкции.

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

Обычно текстовый сегмент является разделяемым, поэтому для часто выполняемых программ, таких как текстовые редакторы, компилятор C, оболочки и т. Д., Должна быть только одна копия. Кроме того, текстовый сегмент часто доступен только для чтения, чтобы программа не могла случайно изменить свои инструкции.

2. Инициализированный сегмент данных:
Инициализированный сегмент данных, обычно называемый просто Сегмент данных. Сегмент данных — это часть виртуального адресного пространства программы, которая содержит глобальные переменные и статические переменные, которые инициализируются программистом.

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

Этот сегмент может быть дополнительно классифицирован на инициализированную область только для чтения и инициализированную область чтения-записи.

Например, глобальная строка, определенная char s [] = «hello world» в C и оператором C, например int debug = 1 вне основного (т. Е. Глобального), будет храниться в инициализированной области чтения-записи. А глобальный оператор C, такой как const char * string = «hello world», заставляет строковый литерал «hello world» храниться в инициализированной области только для чтения, а переменную-строку указателя символов — в инициализированной области чтения-записи.

Пример: static int i = 10 будет сохранено в сегменте данных, а глобальное int i = 10 также будет сохранено в сегменте данных

3. Сегмент неинициализированных данных:
Сегмент неинициализированных данных, часто называемый сегментом «bss», названный в честь древнего оператора ассемблера, который обозначал «блок, начинающийся с символа». Данные в этом сегменте инициализируются ядром в арифметику 0 до начала выполнения программы

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

Например, переменная, объявленная как static int i; будет содержаться в сегменте BSS.
Например, глобальная переменная, объявленная int j; будет содержаться в сегменте BSS.

4. Стек:
Область стека традиционно примыкала к области кучи и росла в противоположном направлении; когда указатель стека встретился с указателем кучи, свободная память была исчерпана. (С современными большими адресными пространствами и методами виртуальной памяти они могут быть размещены почти где угодно, но они все еще обычно растут в противоположных направлениях.)

Область стека содержит программный стек, структуру LIFO, обычно расположенную в верхних частях памяти. На стандартной компьютерной архитектуре ПК x86 она растет до нуля адресов; на некоторых других архитектурах он растет в противоположном направлении. Регистр «указатель стека» отслеживает вершину стека; он корректируется каждый раз, когда значение «помещается» в стек. Набор значений, выдвигаемых для одного вызова функции, называется «стековым фреймом»; Фрейм стека состоит как минимум из обратного адреса.

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

5. Куча:
Куча — это сегмент, где обычно происходит динамическое распределение памяти.

Область кучи начинается в конце сегмента BSS и увеличивается оттуда к более крупным адресам. Область кучи управляется malloc, realloc и free, которые могут использовать системные вызовы brk и sbrk для настройки своего размера (обратите внимание, что использование brk / sbrk и одной «области кучи» не требуется для выполнения контракта malloc / realloc / free; они также могут быть реализованы с использованием mmap для резервирования потенциально несмежных областей виртуальной памяти в виртуальном адресном пространстве процесса) , Область Heap является общей для всех общих библиотек и динамически загружаемых модулей в процессе.
 

enjoynering

Well-known member
Было бы больше толку , если вы вместо ярлыков на чужие высказывания, писали бы свои рассуждения по теме.
вот тут я согласен - пока от rst одни понты и самобахвальство.
 

rst

Member
Было бы больше толку , если вы вместо ярлыков на чужие высказывания, писали бы свои рассуждения по теме.
Я излагал. Пролистайте выше посты.
И о каких "ярлыках" речь - не понял? Вы написали неправду, о чём я и сказал.
 

rst

Member
Типичная схема памяти запущенного процесса
...
Так уже значительно точнее. Хотя есть "но": Сегмент кода совсем не обязательно располагать ниже стека. А в системах с защитой памяти (большинство современных систем) даже лучше наоборот - выше. Чтобы сразу узнать о случае переполнения стека, а не "заметать проблему под ковёр".
Да и взаимное расположение других сегментов друг относительно друга - также как правило произвольно, могут быть размещены как угодно (в пределах своего типа памяти) или как программист захочет.
 

rst

Member
вот тут я согласен - пока от rst одни понты и самобахвальство.
Разложите пожалуйста по пунктам - где именно "понты" и где "самобахвальство"?
А то пока с вашей стороны постоянно только какие-то претензии и обиды капризной принцессы. По делу есть возражения? Я вам чего-то должен? Что именно вас не устраивает в моих ответах?

PS: С вашей стороны я вижу неадекватное поведение: на мои уточняющие вопросы вы не отвечаете; вопросы внятно сформулировать не умеете. Но выдвигаете какие-то претензии. Может стоит сперва посмотреться в зеркало, прежде чем на других ярлыки развешивать? ась?
 

enjoynering

Well-known member
В этом то и проблема - все было сформулировано и дано. Вы же прикинулись шлангом и перешли на личности. претензий нет, просто констатация,фактов.
 

rst

Member
В этом то и проблема - все было сформулировано и дано. Вы же прикинулись шлангом и перешли на личности. претензий нет, просто констатация,фактов.
Так всё-таки: что за "heap" о которой спрашивали? И что за "первый" и "второй" примеры, в которых должна быть экономия этой самой "heap"?
 

tretyakov_sa

Moderator
Команда форума
Так всё-таки: что за "heap" о которой спрашивали? И что за "первый" и "второй" примеры, в которых должна быть экономия этой самой "heap"?
Программа распределяет память и выделяет динамически распределяемую память heap. В нашем случае это доступная оперативная память.
Под переменные будет тратиться какое-то количество этой самой памяти.
Определяя те или иные переменные вы занимаете эту самую память.
Например определяя глобальную переменную int мы займем четыре байта в heap в процессе выполнения программы. Причем если эта переменная глобальная, то эта память будет выделена на всегда от начала выполнения. Если переменная локальная то 4 байта будет выделена в процессе исполнения функции в которой она определена и будет очищена после завершения этой функции. В свою очередь uint8_t выделит всего 1 байт. Казалась бы все верно, но так как процессоры бывают с разным доступом за раз. Одна такая переменная может занять и 4 байта. Здесь вступит в игру способ распределения памяти, что может привести к тому что выделится 4 байта вместо одного. Это динамический процесс. Но не играет особой роли когда у вас памяти много и куча-heap огромна. Но если вы написали код который не контролирует наличие свободной памяти особенно когда heap на исходе это будет приводить к глюкам которые трудно отследить. Именно по этому когда памяти мало а код огромен нужно быть осторожным (да и вообще об этом нужно думать).
Еще несколько примеров для понимания:
Например Если вы Вы определите переменную String test = "hello". То кажется что будет занято 6 байт символы + 0 в конце строки. Но система выделит например 12 байт так как удвоит буфер для добавления в строку символов если это потребуется. Если для добавления потребуется больше памяти строка будет переопределена и в результате займет в два раза больше памяти чем результирующая и это займет не только память но и время.
Таким образом В системе это займет не только heap но и байты во флешь 6 байт, так как это сам код программы.
Но если вы определите String как const String то в heap будет занято 6 байт без возможности расширения строки и к такой строке вам больше ничего добавить не удастся.
Но все выше сказанное очень зависит от компилятора и системы на которой вы работаете.
Поэтому стоит подумать как будет работать код и как обращаться к данным. Не приводит ли стиль программирования к дублированию данных в heap.
Но весь этот разговор уже давно не относится к вопросу топик стартера :)
 
Сверху Снизу