Где хранится значение переменной при выполнении программного кода в оперативной памяти

Обновлено: 18.04.2024

4. Переменные: тип, имя, значение.

В объектно-ориентированном языке программирования Visual Basic переменные используются для хранения и обра­ботки данных в программах.

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

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

Тип переменной . Тип переменных определяется диапа­зоном значений, которые могут принимать переменные, и допустимыми операциями над этими значениями. Значе­ниями переменных числовых типов Byte , Short , Integer , Long , Single , Double являются числа, логического типа Boolean — значения True («истина») или False («ложь»), строкового типа String — последовательности символов.

Различные типы данных требуют для своего хранения в оперативной памяти компьютера различное количество ячеек (байтов) (табл. 2.2).

Таблица 2.2. Некоторые типы переменных в языке Visual Basic 2 010

Возможные значения

Объем занимаемой памяти

Целые неотрицательные числа от 0 до 255

Целые числа от –32 768 до 32 767

Целые числа от –2 147 483 648 до 2 147 483 647

Целые числа от –9 223 372 036 854 до

9 223 372 036 853

Десятичные числа одинарной точности (7-8 значащих цифр) от –1,4·10 –45 до 3,4·10 38

Десятичные числа двойной точности (15-16 значащих цифр) от -5,0·10 –324 до 1,7·10 308

Логическое значение True или False

Строка символов в кодировке Unicode

Даты от 1 января 0001 года до 31 декабря 9999 года и время от 0:00:00 до 23:59:59

Имя переменной. Имена переменных определяют облас­ти оперативной памяти компьютера, в которых хранятся значения переменных. Имя каждой переменной (идентифи­катор) уникально и не может меняться в процессе выполне­ния программы. Имя переменной может состоять из различ­ных символов (латинские и русские буквы, цифры и т. д.), но должно обязательно начинаться с буквы и не должно включать знак точка «.». Количество символов в имени не может быть более 1023, однако для удобства обычно ограни­чиваются несколькими символами.

Объявление переменных. Необходимо объявлять пере­менные, для того чтобы исполнитель программы (компью­тер) «понимал», переменные какого типа используются в программе.

Для объявления переменной используется оператор Dim . С помощью одного оператора можно объявить сразу не­сколько переменных, например:

Dim A As Byte, В As Short, С As Single, D As String, G As Boolean

Присваивание переменным значений. Переменная мо­жет получить или изменить значение с помощью оператора присваивания. При выполнении оператора присваивания переменная, имя которой указано слева от знака равенства, получает значение, которое находится справа от знака ра­венства. Например:

Значение переменной может быть задано числом, стро­кой или логическим значением, а также может быть пред­ставлено с помощью арифметического, строкового или логи­ческого выражения.

Проект «Переменные». Создать проект, в котором объя­вить переменные различных типов, присвоить им значения и вывести значения в поле списка, размещенное на форме.

Создадим графический интерфейс (рис. 2.8).

1. Поместить на форму:

• поле списка ListBox 1 для вывода значений перемен­ных;

• кнопку Button 1 для запуска событийной процедуры.

Создадим событийную процедуру, реализующую присва­ивание значений переменным различных типов. Вывод зна­чений переменных в поле списка произведем с исполь­зованием метода Items . Add () , аргументами которого будут переменные.

2. Dim A As Byte, В As Short, С As Single, D As String, G As Boolean

Private Sub Button1_Click (. )

End Sub

3. Запустить проект на выполне­ние. После щелчка по кнопке начнет выполняться событийная процедура, в которой будут вы­полнены операции присваива­ния (в отведенные переменным области оперативной памяти бу­дут записаны их значения).

Затем с помощью метода Items . Add () будет произведен вывод значений переменных в поле списка. В этом процессе значения переменных считываются из оперативной памяти и печатаются в столбик в поле спи­ска (см. рис. 2.8).


Рис. 2.8. Проект «Переменные»

Проанализируем процесс выполнения программы компьютером. После запуска проекта оператор объявления переменных Dim отведет в оперативной памяти для их хра­нения необходимое количество ячеек (табл. 2.3):

учитывая, что память разделена на четыре сегмента: данные, куча, стек и код, где хранятся глобальные переменные, статические переменные, постоянные типы данных, локальные переменные (определенные и объявленные в функциях), переменные (в основной функции), указатели и динамически выделенное пространство (с использованием malloc и calloc)?

Я думаю, что они будут распределены следующим образом:

  • глобальные переменные -------> данные
  • статические переменные ------- >данные
  • постоянные типы данных - - - - - > код
  • локальные переменные (объявленные и определенные в функциях) --------> стек
  • переменные, объявленные и определенные в основной функции - - - - - > heap
  • указатели (например, char *arr , int *arr ) -------> кучи
  • динамически выделенное пространство (с помощью malloc и calloc) --------> стек

Я имею в виду эти переменные только из C перспектива.

пожалуйста, поправьте меня, если я ошибаюсь, поскольку я новичок в C.

вы получили некоторые из них правильно, но тот, кто написал вопросы, обманул вас по крайней мере на один вопрос:

  • глобальные переменные -------> данные (правильные)
  • статические переменные -------> данные (правильные)
  • постоянные типы данных - - - - - > код и / или данные. Рассмотрим строковые литералы для ситуации, когда сама константа будет храниться в сегменте данных, а ссылки на нее будут встроены в код
  • локальные переменные(объявленные и определено в функциях) --------> стек (правильно)
  • переменные, объявленные и определенные в -0-->кучу также стек (учитель пытался вас обмануть)
  • указателей(пример: char *arr , int *arr ) -------> кучу данные или стек, в зависимости от контекста. C позволяет объявить глобальный или static указатель, в этом случае сам указатель окажется в сегменте данных.
  • динамически выделенную память(используя malloc , calloc , realloc ) --------> стек кучу

стоит отметить, что "стек" официально называется "автоматический класс памяти".

для тех будущих посетителей, которые могут быть заинтересованы в знании об этих сегментах памяти, я пишу важные моменты о 5 сегментах памяти в C:

некоторые головы:

  1. всякий раз, когда программа C выполняется, некоторая память выделяется в ОЗУ для выполнения программы. Эта память используется для хранения наиболее часто выполняемого кода (двоичных данных), программные переменные и т. д. Ниже сегменты памяти говорит о же:
  2. обычно существует три типа переменных:
    • локальные переменные (также называемые автоматическими переменными в C)
    • глобальные переменные
    • статические переменные
    • вы можете иметь глобальные статические или локальные статические переменные, но вышеуказанные три являются родительскими типами.

5 сегментов памяти в C:

  • код сегмент, также называемый сегментом текста, - это область памяти, содержащая часто выполняемый код.
  • сегмент кода часто доступен только для чтения, чтобы избежать риска переопределения программными ошибками, такими как переполнение буфера и т. д.
  • сегмент кода не содержит переменных программы, таких как локальная переменная (также называется автоматическими переменными в C), глобальные переменные и т. д.
  • на основе реализации C сегмент кода также может содержит строковые литералы только для чтения. Например, когда вы делаете printf("Hello, world") затем строка "Hello, world" создается в сегменте кода/текста. Вы можете проверить это, используя в ОС Linux.

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

2. Неинициализированный сегмент данных

  • этот сегмент также известен как bss.
  • это часть памяти, которая содержит:
    1. неинициализированные глобальные переменные(включая указатель переменных)
    2. неинициализированные константы глобальные переменные.
    3. неинициализированный локальный статический переменные.
  • любая глобальная или статическая локальная переменная, которая не инициализирована будет храниться в неинициализированный сегмент данных
  • например: глобальная переменная int globalVar; или статическая локальная переменная static int localStatic; будет храниться в сегмент неинициализированных данных.
  • если вы объявляете глобальную переменную и инициализировать ее как 0 или NULL тогда все равно он перейдет к неинициализированному сегменту данных или bss.

3. Инициализированный сегмент данных

  • этот сегмент магазинах:
    1. инициализированные глобальные переменные(включая указатель переменных)
    2. значение константы глобальные переменные.
    3. инициализированные локальные статические переменные.
  • например: глобальная переменная int globalVar = 1; или статический локальная переменная static int localStatic = 1; будет храниться в инициализировать сегмент данных.
  • этот сегмент может быть далее классифицируется в инициализированной области только для чтения и инициализированной области чтения и записи. инициализированные постоянные глобальные переменные будут входить в инициализированную область только для чтения, а переменные, значения которых могут быть изменены во время выполнения, будут входить в инициализированную область чтения и записи.
  • размер этого сегмента определяется размер значения в исходном коде программы и не меняются во время выполнения.
  • сегмент стека используется для хранения переменных, которые создаются внутри функции (функция может быть основной функцией или пользовательской функцией), переменная как
    1. локальные переменные функции (включая указатель переменные)
    2. аргументы, переданные функции
    3. обратный адрес
  • переменные, хранящиеся в стеке, будут удалены, как только закончится выполнение функции.
  • этот сегмент предназначен для поддержки динамического выделения памяти. Если программист хочет выделить некоторые память динамически, то в C это делается с помощью malloc , calloc или realloc методы.
  • например, когда int* prt = malloc(sizeof(int) * 2) тогда восемь байтов будут выделены в куче, и адрес памяти этого местоположения будет возвращен и сохранен в ptr переменной. The ptr переменная будет находиться либо в стеке, либо в сегменте данных в зависимости от способа ее объявления/использования.

исправлены неправильные предложения

локальные постоянные переменные - - - - - > stack

инициализированная глобальная постоянная переменная - - - - - > сегмент данных

неинициализированная глобальная постоянная переменная - - - - - > bss

переменные, объявленные и определенные в основной функции - - - - - > stack

указатели (например: char * arr, int * arr) -------> размер этой переменной указателя будет находиться в стеке.

считайте, что вы выделение памяти из n байт (используя malloc или calloc ) динамически, а затем делает переменную указателя, чтобы указать ее. Теперь что n байты памяти находятся в куче, а переменная указателя requries 4 байта (если 64-битная машина 8 байт), которая будет в стеке для хранения начального указателя n байт блока памяти.

Примечание: переменные указателя могут указывать на память любого сегмента.

динамически выделенное пространство(с помощью malloc, calloc) --------> кучи

популярная архитектура рабочего стола делит виртуальную память процесса на несколько сегментов:

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

сегмент данных: содержит глобальные переменные (т. е. объекты со статической связью). Подразделяется на данные только для чтения (например, строковые константы) и неинициализированные данные ("BSS").

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

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

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

Я имею в виду эти переменные только с точки зрения Си.

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

указатели (например: char * arr, int * arr) ------- > куча

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

Учитывая, что память разделена на четыре сегмента: данные, куча, стек и код, где находятся глобальные переменные, статические переменные, постоянные типы данных, локальные переменные (определенные и объявленные в функциях), переменные (в основной функции), указатели и динамически выделенное пространство (используя malloc и calloc) хранится в памяти?

Я думаю, что они будут распределены следующим образом:

  • Глобальные переменные -------> данные
  • Статические переменные -------> данные
  • Постоянные типы данных -----> код
  • Локальные переменные (объявленные и определенные в функциях) --------> stack
  • Переменные, объявленные и определенные в основной функции -----> heap
  • Указатели (например, char *arr , int *arr ) -------> кучного
  • Динамически распределяемое пространство (используя malloc и calloc) --------> стек

Я имею в виду эти переменные только с точки зрения Си.

Пожалуйста, поправьте меня, если я ошибаюсь, поскольку я новичок в C.

main это просто другая функция. Переменные помещаются в стек, если malloc только они не похожи на другие. указатели (обычно) хранятся в стеке. Память, на которую они указывают (обычно выделяемая через malloc / calloc), находится (обычно) в куче. динамически распределяемое пространство (используя malloc, calloc) --------> heap переменные объявлены и определены в основной функции -----> stack

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

  • глобальные переменные -------> данные (правильно)
  • статические переменные -------> данные (правильно)
  • постоянные типы данных -----> код и / или данные. Рассмотрим строковые литералы для ситуации, когда сама константа будет храниться в сегменте данных, а ссылки на нее будут встроены в код
  • локальные переменные (объявленные и определенные в функциях) --------> stack (правильно)
  • переменные объявлены и определены в main функции -----> heap также стек (учитель пытался обмануть вас)
  • указатели (например: char *arr , int *arr ) -------> куча данных или стека, в зависимости от контекста. C позволяет вам объявить глобальный или static указатель, и в этом случае сам указатель окажется в сегменте данных.
  • динамически распределяемой пространство (используя malloc , calloc , realloc ) --------> стека кучи

Стоит отметить, что «стек» официально называется «классом автоматического хранения».

Также стоит упомянуть, что кучи официально ничего не называют вообще. Выделенная память приходит откуда-то, в стандарте нет названия для этого «где-то». В некоторых системах (а именно в Linux и * BSD) также существует система, alloca которая работает аналогично malloc , но выполняет распределение в стеке. Куда идут переменные const, объявленные внутри метода? @Ravi Там же, где и остальные константы (точка № 3 выше). Я использую GCC 4.8.1, и он не хранит переменную const local to main в сегменте DATA. Ниже приведен код и карта памяти для 3 таких программ: Код 1: int main (void) КАРТА ПАМЯТИ ВЫШЕ: текстовые данные bss dec hex имя файла 7264 1688 1040 9992 2708 a.exe КАРТА ПАМЯТИ 2: текстовые данные bss dec hex имя файла 7280 1688 1040 10008 2718 a.exe КАРТА ПАМЯТИ 3: текстовые данные bss dec hex имя файла 7280 1688 1040 10008 2718 a.exe

Для тех будущих посетителей, которым может быть интересно узнать об этих сегментах памяти, я пишу важные замечания о 5 сегментах памяти в C:

Некоторые головы:

  1. Всякий раз, когда выполняется программа на C, в оперативной памяти выделяется некоторая память для выполнения программы. Эта память используется для хранения часто исполняемого кода (двоичные данные), программных переменных и т. Д. Сегменты памяти ниже говорят о том же:
  2. Обычно существует три типа переменных:
    • Локальные переменные (также называемые автоматическими переменными в C)
    • Глобальные переменные
    • Статические переменные
    • Вы можете иметь глобальные статические или локальные статические переменные, но вышеприведенные три являются родительскими типами.

5 сегментов памяти в C:

  • Сегмент кода, также называемый текстовым сегментом, является областью памяти, которая содержит часто выполняемый код.
  • Сегмент кода часто доступен только для чтения, чтобы избежать риска переопределения при программировании ошибок, таких как переполнение буфера и т. Д.
  • Сегмент кода не содержит программных переменных, таких как локальные переменные ( также называемые автоматическими переменными в C ), глобальные переменные и т. Д.
  • На основе реализации C сегмент кода может также содержать строковые литералы, доступные только для чтения. Например, когда вы делаете, printf("Hello, world") то строка «Hello, world» создается в сегменте кода / текста. Вы можете проверить это используя size команды в ОС Linux.

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

2. Неинициализированный сегмент данных

  • Этот сегмент также известен как BSS .
  • Это часть памяти, которая содержит:
    1. Неинициализированные глобальные переменные(включая переменные-указатели)
    2. Неинициализированные постоянные глобальные переменные .
    3. Неинициализированные локальные статические переменные .
  • Любая глобальная или статическая локальная переменная, которая не инициализирована, будет сохранена в неинициализированном сегменте данных.
  • Например: глобальная переменная int globalVar; или статическая локальная переменная static int localStatic; будут храниться в неинициализированном сегменте данных.
  • Если вы объявляете глобальную переменную и инициализируете ее как 0 или NULL тогда, она все равно перейдет к неинициализированному сегменту данных или bss.

3. Инициализированный сегмент данных

  • Этот сегмент магазинов:
    1. Инициализированные глобальные переменные(включая переменные-указатели)
    2. Инициализированные постоянные глобальные переменные .
    3. Инициализированные локальные статические переменные .
  • Например: глобальная переменная int globalVar = 1; или статическая локальная переменная static int localStatic = 1; будут храниться в инициализированном сегменте данных.
  • Этот сегмент может быть дополнительно классифицирован на инициализированную область только для чтения и инициализированную область чтения-записи . Инициализированные постоянные глобальные переменные попадут в инициализированную область только для чтения, а переменные, значения которых могут быть изменены во время выполнения, попадут в инициализированную область чтения-записи .
  • Размер этого сегмента определяется размером значений в исходном коде программы и не изменяется во время выполнения .
  • Сегмент стека используется для хранения переменных, которые создаются внутри функций ( функция может быть основной или определяемой пользователем функцией ), например, переменная
    1. Локальные переменные функции (включая переменные-указатели)
    2. Аргументы переданы в функцию
    3. Обратный адрес
  • Переменные, хранящиеся в стеке, будут удалены, как только закончится выполнение функции.
  • Этот сегмент должен поддерживать динамическое распределение памяти. Если программист хочет выделить память динамически , то в C это делается с помощью malloc , calloc или realloc методов.
  • Например, когда int* prt = malloc(sizeof(int) * 2) в куче будет выделено восемь байтов, адрес памяти этого местоположения будет возвращен и сохранен в ptr переменной. ptr Переменный будут либо на стек данных или сегменты в зависимости от того, как она объявлена / используются.
Не следует ли это инициализировать, а не инициализировать в 3. Инициализированный сегмент данных. Re «хранится в неинициализированном сегменте данных» (несколько экземпляров): Вы имеете в виду «хранится в неинициализированном сегменте данных» ? @PeterMortensen Я имею в виду обе вещи. «Любая глобальная или статическая локальная переменная, которая не инициализирована, будет сохранена в неинициализированном сегменте данных» Как мы можем иметь глобальную статическую переменную в C? в разделе "некоторые заголовки" я обнаружил этот пункт "У вас могут быть глобальные статические или локальные статические переменные, но вышеприведенные три являются родительскими типами" в котором вы упомянули термин «глобальная статика». Моя точка зрения - статическая переменная не может быть глобальной. т. е. если какая-либо переменная должна быть глобальной, она должна быть доступна до завершения выполнения программы. Пожалуйста, объясните и помогите, если я ошибаюсь.

Исправил ваши неправильные предложения

локальные постоянные переменные -----> стек

инициализированная глобальная постоянная переменная -----> сегмент данных

неинициализированная глобальная постоянная переменная -----> bss

переменные объявлены и определены в основной функции -----> stack

указатели (например: char * arr, int * arr) -------> размер этой переменной указателя будет в стеке.

Учтите, что вы выделяете память из n байтов (используя malloc или calloc ) динамически, а затем делаете указатель переменным, чтобы указать его. Теперь, когда n байты памяти находятся в куче, а переменная-указатель требует 4 байта (если 64-битная машина 8 байтов), которые будут в стеке для хранения начального указателя n байтов блока памяти.

Примечание: переменные-указатели могут указывать на память любого сегмента.

динамически распределяемое пространство (используя malloc, calloc) --------> heap

указатели могут быть либо в стеке, либо в куче (см. особенно: указатели на указатели) @airza: сейчас обновлено. На самом деле я обновлял только эти детали :) На следующей карте памяти, не могли бы вы указать, где находится стек и куча? Я не уверен, что это правильный вопрос, так как стек и память могут быть применимы только во время выполнения. КАРТА ПАМЯТИ: «текстовые данные bss dec hex имя файла 7280 1688 1040 10008 2718 a.exe»

Популярная настольная архитектура делит виртуальную память процесса на несколько сегментов :

Текстовый сегмент: содержит исполняемый код. Указатель инструкции принимает значения в этом диапазоне.

Сегмент данных: содержит глобальные переменные (то есть объекты со статической связью). Подразделяются на данные только для чтения (например, строковые константы) и неинициализированные данные («BSS»).

Сегмент стека: содержит динамическую память для программы, т.е. свободное хранилище («куча») и локальные кадры стека для всех потоков. Традиционно стек C и куча C врастали в сегмент стека с противоположных концов, но я считаю, что от практики отказались, потому что это слишком небезопасно.

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

На других платформах, таких как старый реальный режим x86 или на встроенных устройствах, очевидно, что все может быть совершенно иначе.

«Я считаю, что от практики отказались, потому что она слишком небезопасна» - и делает невозможным внедрение потоков, так как тогда вам нужно более одного стека на программу, и все они не могут быть в конце :-) @SteveJessop: Да, я тоже так думал. Но потоки существовали долгое время - я не знаю, выросли ли все стеки потоков назад или же они выросли бы как куча . во всяком случае, в настоящее время все идет в одном направлении, и есть охрана страницы.

Я имею в виду эти переменные только с точки зрения Си.

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

Одна вещь, которую нужно помнить о хранилище - это правило « как будто» . Компилятору не требуется помещать переменную в определенное место - вместо этого он может размещать ее там, где ему заблагорассудится, до тех пор, пока скомпилированная программа ведет себя так, как если бы она выполнялась на абстрактной машине C в соответствии с правилами абстрактной машины C. Это относится ко всем хранения длительностей . Например:

  • переменная, к которой не обращаются все, может быть полностью удалена - она ​​не имеет хранения . нигде. Пример - посмотрите, как есть 42 в сгенерированном коде сборки, но нет признаков 404 .
  • переменная с автоматическим сроком хранения, для которой не указан адрес, вообще не должна храниться в памяти. Примером может быть переменная цикла.
  • переменная, которая есть const или фактически const не должна быть в памяти. Пример - компилятор может доказать это foo эффективно const и встраивает его использование в код. bar имеет внешнюю связь, и компилятор не может доказать, что он не будет изменен вне текущего модуля, поэтому он не встроен.
  • объект, выделенный без malloc необходимости, не должен находиться в памяти, выделенной из кучи! Пример - обратите внимание, что в коде нет вызова malloc и значение 42 никогда не сохраняется в памяти, оно сохраняется в регистре!
  • таким образом, объект, который был выделен malloc и ссылка потеряна без освобождения объекта, free не нуждается в утечке памяти .
  • malloc необязательный объект не должен быть в куче ниже программы break ( sbrk(0) ) в Unixen .

указатели (например: char * arr, int * arr) -------> heap

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

Утверждения о main и динамически распределенных переменных тоже неверны Не только в стеке или сегменте данных. Подумайте о указателе, который указывает на массив указателей. В этом случае указатели в массиве хранятся в куче.
  • Переменные / автоматические переменные ---> секция стека
  • Динамически размещенные переменные ---> раздел кучи
  • Инициализированные глобальные переменные -> раздел данных
  • Неинициализированные глобальные переменные -> раздел данных (bss)
  • Статические переменные -> раздел данных
  • Строковые константы -> текстовая секция / секция кода
  • Функции -> текстовая секция / секция кода
  • Текстовый код -> текстовый раздел / кодовый раздел
  • Регистры -> регистры процессора
  • Ввод командной строки -> раздел среды / командной строки
  • Переменные среды -> раздел среды / командной строки
Что такое раздел среды / командной строки? Они существуют в Linux?

Linux минимально работоспособные примеры с анализом дизассемблирования

Поскольку это детали реализации, не указанные стандартами, давайте просто посмотрим, что делает компилятор в конкретной реализации.

В этом ответе я либо сошлюсь на конкретные ответы, которые делают анализ, либо предоставлю анализ прямо здесь, и суммирую все результаты здесь.

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

Локальная переменная внутри функции

Будь то main или любая другая функция:

  • -O0 : stack
  • -O3 : регистрирует, если они не проливаются, укладываются иначе

Глобальные переменные и static функциональные переменные

  • если инициализирован 0 или не инициализирован (и, следовательно, неявно инициализирован 0 ): .bss section, см. также: Почему требуется сегмент .bss?
  • иначе: .data раздел

char * и char c[]

TODO будут помещать в стек очень большие строковые литералы? Или .data ? Или компиляция не удалась?

Аргументы функции

Тогда, как показано в разделе Что означает <value optimized out> в gdb? , -O0 То хлебает все в стек, в то время как -O3 пытается максимально использовать регистры.

Однако, если функция встроена, они обрабатываются как обычные локальные.

const

Я полагаю, что это не имеет значения, потому что вы можете настроить его.

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

указатели

Они являются переменными (которые содержат адреса, которые являются числами), так же, как и все остальные :-)

таНос

Вопрос не имеет особого смысла malloc , так как malloc является функцией, и в:

*i переменная, которая содержит адрес, поэтому она попадает в приведенный выше случай.

Что касается того, как malloc работает внутренне, когда вы называете его ядром Linux, он помечает определенные адреса как доступные для записи в своих внутренних структурах данных, и когда программа касается их изначально, происходит сбой, и ядро ​​активирует таблицы страниц, что дает доступ без segfaul: как работает подкачка x86?

Однако обратите внимание, что это в основном именно то, что exec делает системный вызов под капотом, когда вы пытаетесь запустить исполняемый файл: он отмечает страницы, на которые он хочет загрузить, и записывает туда программу, см. Также: Как ядро ​​получает исполняемый двоичный файл, работающий под линукс? За исключением того, что exec имеет некоторые дополнительные ограничения на то, куда загружать (например, если код не перемещается ).

Точный системный вызов используется для malloc это mmap в современных реализациях 2020, а в прошлом brk был использован: Имеет ли таНос () использование битый () или ММАП ()?


У каждого компьютера есть оперативная память . Что же это такое, какими свойствами обладает и, самое главное, какая нам от этого польза?

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

Что же такое оперативная память и на что она похожа?


Процессор умеет исполнять команды из загруженной в память программы. Почти все команды процессора — это что-то типа: взять данные из некоторых ячеек → сделать с ними что-то → результат поместить в другие ячейки

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

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

На заре компьютерной отрасли программы работали просто с номерами ячеек памяти, но потом для удобства программистов ячейкам стали давать имена. Уникальное имя переменной — это в первую очередь для удобства программистов: программа во время работы отлично справилась бы и с номерами.

2. Переменные в памяти

Всего в Java есть 4 типа данных для хранения целых чисел. Это byte , short , int и long .

Тип Размер, байт Происхождение имени
byte 1 Byte , т.к. занимает один байт памяти
short 2 Сокращение от Short Integer
int 4 Сокращение от Integer
long 8 Сокращение от Long Integer

Также в Java есть 2 вещественных типа — float и double:

Тип Размер, байт Происхождение имени
float 4 Сокращение от Floating Point Number
double 8 Сокращение от Double Float

Каждый раз, когда выполнение программы доходит до команды создания переменной, ей выделяется небольшая область памяти (размер зависит от типа переменной).

Адресом переменной считается адрес первой ячейки выделенного под нее блока памяти.

Java-программам запрещено напрямую обращаться к памяти. Вся работа с памятью происходит только через Java-машину.

3. Тип String в памяти

Тип String может хранить большие объемы данных, поэтому это не просто тип данных, а полноценный класс.

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


Переменная a типа int занимает 4 байта и хранит значение 1 .

Переменная b типа int занимает 4 байта и хранит значение 10,555 . Запятая - это не дробная часть числа, а разделение разрядов. Дробная часть отделяется точкой

Переменная d типа double занимает 8 байт и хранит значение 13.001 .

Переменная str типа String занимает 4 байта и хранит значение G13 — адрес первой ячейки объекта, содержащего текст.

Объект типа String (содержащий текст) хранится отдельным блоком памяти. Адрес его первой ячейки хранится в переменной str .

4. Почему в программировании всё нумеруют с нуля

Люди очень часто удивляются, почему в программировании почти везде принято считать с нуля. Дело в том, что есть очень много ситуаций, когда считать с нуля удобнее (хотя есть и ситуации, когда удобнее считать с 1 ).

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

Читайте также: