Учитывая, что память разделена на четыре сегмента: данные, куча, стек и код, где находятся глобальные переменные, статические переменные, постоянные типы данных, локальные переменные (определенные и объявленные в функциях), переменные (в основной функции), указатели и динамически выделенное пространство (используя malloc и calloc) хранится в памяти?
Я думаю, что они будут распределены следующим образом:
- Глобальные переменные -------> данные
- Статические переменные -------> данные
- Постоянные типы данных -----> код
- Локальные переменные (объявленные и определенные в функциях) --------> stack
- Переменные, объявленные и определенные в основной функции -----> heap
- Указатели (например,
char *arr
,int *arr
) -------> кучного - Динамически распределяемое пространство (используя malloc и calloc) --------> стек
Я имею в виду эти переменные только с точки зрения Си.
Пожалуйста, поправьте меня, если я ошибаюсь, поскольку я новичок в C.
c
memory
memory-management
types
starkk92
источник
источник
main
это просто другая функция. Переменные помещаются в стек, еслиmalloc
только они не похожи на другие.Ответы:
Вы правильно поняли некоторые из них, но тот, кто написал вопросы, обманул вас, по крайней мере, на один вопрос:
main
функции ----->heapтакже стек (учитель пытался обмануть вас)char *arr
,int *arr
) ------->кучаданных или стека, в зависимости от контекста. C позволяет вам объявить глобальный илиstatic
указатель, и в этом случае сам указатель окажется в сегменте данных.malloc
,calloc
,realloc
) -------->стекакучиСтоит отметить, что «стек» официально называется «классом автоматического хранения».
источник
alloca
которая работает аналогичноmalloc
, но выполняет распределение в стеке.Для тех будущих посетителей, которым может быть интересно узнать об этих сегментах памяти, я пишу важные замечания о 5 сегментах памяти в C:
Некоторые головы:
5 сегментов памяти в C:
1. Сегмент кода
printf("Hello, world")
то строка «Hello, world» создается в сегменте кода / текста. Вы можете проверить это используяsize
команды в ОС Linux.Сегмент данных
Сегмент данных разделен на две части ниже и, как правило, находится ниже области кучи или в некоторых реализациях выше стека, но сегмент данных никогда не лежит между областью кучи и стека.
2. Неинициализированный сегмент данных
int globalVar;
или статическая локальная переменнаяstatic int localStatic;
будут храниться в неинициализированном сегменте данных.0
илиNULL
тогда, она все равно перейдет к неинициализированному сегменту данных или bss.3. Инициализированный сегмент данных
int globalVar = 1;
или статическая локальная переменнаяstatic int localStatic = 1;
будут храниться в инициализированном сегменте данных.4. Сегмент стека
5. Сегмент кучи
malloc
,calloc
илиrealloc
методов.int* prt = malloc(sizeof(int) * 2)
в куче будет выделено восемь байтов, адрес памяти этого местоположения будет возвращен и сохранен вptr
переменной.ptr
Переменный будут либо на стек данных или сегменты в зависимости от того, как она объявлена / используются.источник
Исправил ваши неправильные предложения
локальные постоянные переменные -----> стек
инициализированная глобальная постоянная переменная -----> сегмент данных
неинициализированная глобальная постоянная переменная -----> bss
переменные объявлены и определены в основной функции -----> stack
указатели (например: char * arr, int * arr) -------> размер этой переменной указателя будет в стеке.
Учтите, что вы выделяете память из n байтов (используя
malloc
илиcalloc
) динамически, а затем делаете указатель переменным, чтобы указать его. Теперь, когдаn
байты памяти находятся в куче, а переменная-указатель требует 4 байта (если 64-битная машина 8 байтов), которые будут в стеке для хранения начального указателяn
байтов блока памяти.Примечание: переменные-указатели могут указывать на память любого сегмента.
динамически распределяемое пространство (используя malloc, calloc) --------> heap
источник
Популярная настольная архитектура делит виртуальную память процесса на несколько сегментов :
Текстовый сегмент: содержит исполняемый код. Указатель инструкции принимает значения в этом диапазоне.
Сегмент данных: содержит глобальные переменные (то есть объекты со статической связью). Подразделяются на данные только для чтения (например, строковые константы) и неинициализированные данные («BSS»).
Сегмент стека: содержит динамическую память для программы, т.е. свободное хранилище («куча») и локальные кадры стека для всех потоков. Традиционно стек C и куча C врастали в сегмент стека с противоположных концов, но я считаю, что от практики отказались, потому что это слишком небезопасно.
Программа AC обычно помещает объекты со статической продолжительностью хранения в сегмент данных, динамически распределяемые объекты в бесплатном хранилище и автоматические объекты в стек вызовов потока, в котором она живет.
На других платформах, таких как старый реальный режим x86 или на встроенных устройствах, очевидно, что все может быть совершенно иначе.
источник
С точки зрения языка Си все, что имеет значение, это степень, область применения, связь и доступ; как именно элементы отображаются в разные сегменты памяти, зависит от конкретной реализации, и это будет варьироваться. Стандартный язык не говорить о сегментах памяти у всех . Большинство современных архитектур действуют в основном одинаково; переменные области видимости и аргументы функций будут выделяться из стека, области видимости файлов и статические переменные будут выделяться из сегмента данных или кода, динамическая память выделяется из кучи, некоторые постоянные данные будут храниться в сегментах только для чтения. , и т.д.
источник
Одна вещь, которую нужно помнить о хранилище - это правило « как будто» . Компилятору не требуется помещать переменную в определенное место - вместо этого он может размещать ее там, где ему заблагорассудится, до тех пор, пока скомпилированная программа ведет себя так, как если бы она выполнялась на абстрактной машине C в соответствии с правилами абстрактной машины C. Это относится ко всем хранения длительностей . Например:
42
в сгенерированном коде сборки, но нет признаков404
.const
или фактическиconst
не должна быть в памяти. Пример - компилятор может доказать этоfoo
эффективноconst
и встраивает его использование в код.bar
имеет внешнюю связь, и компилятор не может доказать, что он не будет изменен вне текущего модуля, поэтому он не встроен.malloc
необходимости, не должен находиться в памяти, выделенной из кучи! Пример - обратите внимание, что в коде нет вызоваmalloc
и значение 42 никогда не сохраняется в памяти, оно сохраняется в регистре!malloc
и ссылка потеряна без освобождения объекта,free
не нуждается в утечке памяти ...malloc
необязательный объект не должен быть в куче ниже программы break (sbrk(0)
) в Unixen ...источник
Нет, они могут быть в стеке или в сегменте данных. Они могут указывать куда угодно.
источник
main
и динамически распределенных переменных тоже неверныисточник
Linux минимально работоспособные примеры с анализом дизассемблирования
Поскольку это детали реализации, не указанные стандартами, давайте просто посмотрим, что делает компилятор в конкретной реализации.
В этом ответе я либо сошлюсь на конкретные ответы, которые делают анализ, либо предоставлю анализ прямо здесь, и суммирую все результаты здесь.
Все они представлены в различных версиях Ubuntu / GCC, и результаты, вероятно, довольно стабильны во всех версиях, но если мы найдем какие-либо варианты, давайте уточним более точные версии.
Локальная переменная внутри функции
Будь то
main
или любая другая функция:Как показано на: Что означает <value optimized out> в gdb?
-O0
: stack-O3
: регистрирует, если они не проливаются, укладываются иначеЧтобы узнать, почему стек существует, смотрите: Какова функция инструкций push / pop, используемых для регистров в сборке x86?
Глобальные переменные и
static
функциональные переменные0
или не инициализирован (и, следовательно, неявно инициализирован0
):.bss
section, см. также: Почему требуется сегмент .bss?.data
разделchar *
иchar c[]
Как показано на: Где хранятся статические переменные в C и C ++?
TODO будут помещать в стек очень большие строковые литералы? Или
.data
? Или компиляция не удалась?Аргументы функции
Должны пройти соответствующее соглашение о вызовах, например: https://en.wikipedia.org/wiki/X86_calling_conventions для X86, в котором указываются либо конкретные регистры, либо места в стеке для каждой переменной.
Тогда, как показано в разделе Что означает <value optimized out> в gdb? ,
-O0
То хлебает все в стек, в то время как-O3
пытается максимально использовать регистры.Однако, если функция встроена, они обрабатываются как обычные локальные.
const
Я полагаю, что это не имеет значения, потому что вы можете настроить его.
И наоборот, если компилятор может определить, что некоторые данные никогда не записываются, он теоретически может поместить их,
.rodata
даже если не const.Анализ ТОДО.
указатели
Они являются переменными (которые содержат адреса, которые являются числами), так же, как и все остальные :-)
таНос
Вопрос не имеет особого смысла
malloc
, так какmalloc
является функцией, и в:*i
переменная, которая содержит адрес, поэтому она попадает в приведенный выше случай.Что касается того, как malloc работает внутренне, когда вы называете его ядром Linux, он помечает определенные адреса как доступные для записи в своих внутренних структурах данных, и когда программа касается их изначально, происходит сбой, и ядро активирует таблицы страниц, что дает доступ без segfaul: как работает подкачка x86?
Однако обратите внимание, что это в основном именно то, что
exec
делает системный вызов под капотом, когда вы пытаетесь запустить исполняемый файл: он отмечает страницы, на которые он хочет загрузить, и записывает туда программу, см. Также: Как ядро получает исполняемый двоичный файл, работающий под линукс? За исключением того, чтоexec
имеет некоторые дополнительные ограничения на то, куда загружать (например, если код не перемещается ).Точный системный вызов используется для
malloc
этоmmap
в современных реализациях 2020, а в прошломbrk
был использован: Имеет ли таНос () использование битый () или ММАП ()?Динамические библиотеки
Как правило, получить
mmap
доступ к памяти: /unix/226524/what-system-call-is-used-to-load-libraries-in-linux/462710#462710переменные окружения и
main
sargv
Выше начального стека: /unix/75939/where-is-the-environment-string-actual-stored TODO, почему не в .data?
источник