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

Как он знает, где моя ценность в памяти?

Когда я пишу программу и говорю ей int c=5, она помещает значение 5 в немного ее памяти, но как она помнит, какой из них? Единственный способ, о котором я мог думать, - это иметь еще немного памяти, чтобы рассказать об этом, но тогда он должен был бы помнить, где он это сохранил, так как он помнит, где все?

4b9b3361

Ответ 1

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

При компиляции вашей программы компилятор проверяет ваш код, чтобы найти все переменные. Некоторые переменные будут глобальными (или статическими), а некоторые будут локальными. Для статических переменных присваивает им фиксированные адреса памяти. Эти адреса, вероятно, будут последовательными, и они начнутся с определенного значения. Из-за сегментации памяти на большинстве архитектур (и механизмов виртуальной памяти) каждое приложение может (потенциально) использовать одни и те же адреса памяти. Таким образом, если мы предполагаем, что для программ пространства памяти разрешено использовать начальные значения в 0 для нашего примера, каждая программа, которую вы компилируете, поместит первую глобальную переменную в местоположение 0. Если эта переменная составляла 4 байта, следующая была бы в местоположении 4, и т.д. Они не будут конфликтовать с другими программами, запущенными в вашей системе, потому что на самом деле они отображаются в произвольном последовательном разделе памяти во время выполнения. Вот почему он может назначить фиксированный адрес во время компиляции, не беспокоясь о том, чтобы поразить другие программы.

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

Ответ 2

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

Это, по крайней мере, общий принцип. На самом деле это будет более полно, но все-таки та же основная идея.

Ответ 3

read Переменная (программирование) - Распределение памяти:
http://en.wikipedia.org/wiki/Variable_(programming)#Memory_allocation

вот текст из ссылки (если вы действительно не хотите туда ехать, но вам не хватает всех ссылок в тексте):

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

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

Объекты, выделенные из кучи, должны быть исправленными, особенно когда объекты больше не нужны. В собранный мусором язык (например, С#, Java и Lisp), время выполнения среда автоматически восстанавливается объекты, когда существующие переменные не могут дольше относятся к ним. В не связанные с мусором языки, такие как C, программа (и программист) должен явно выделять память, и затем освободите его, чтобы вернуть его Память. Несоблюдение этого приводит к утечки памяти, в которых куча истощается по мере запуска программы, рискуя возможный отказ от истощения доступной памяти.

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

Ответ 4

Там многоступенчатый танец, который превращает c = 5 в машинные инструкции для обновления местоположения в памяти.

  • Компилятор генерирует код в двух частях. Там часть инструкции (загрузите регистр с адресом C, загрузите регистр в литерал 5, магазин). И там часть распределения данных (оставьте 4 байта комнаты со смещением 0 для переменной, известной как "C" ).

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

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

  • Когда выполняется фактическая инструкция "store", ОС должна видеть, действительно ли ссылочная страница данных находится в физической памяти. Он может быть в файле подкачки и должен быть загружен в физическую память. Используемый виртуальный адрес преобразуется в физический адрес расположения памяти.

Ответ 5

Он встроен в программу.

В принципе, когда программа компилируется в машинный язык, она становится серией инструкций. В некоторых инструкциях есть встроенные в них адреса памяти, и это, так сказать, "конец цепочки". Компилятор решает, где будет находиться каждая переменная, и записывает эту информацию в исполняемый файл. (Помните, что компилятор является РАЗЛИЧНОЙ программой для программы, которую вы пишете, просто сосредоточьтесь на том, как работает ваша собственная программа на данный момент.)

Например,

ADD [1A56], 15

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

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

Я надеюсь, что это прояснит ситуацию.

Ответ 6

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

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

Переменные, которые вы используете, представляют собой еще один слой меток. Это облегчает вам отслеживание. То, как переменные хранятся внутри, может иметь на них очень сложные или загадочные ярлыки, но все, о чем вам нужно беспокоиться, - это то, как вы ссылаетесь на них в своем коде. Оставайтесь последовательными, используйте хорошие имена переменных и следите за тем, что вы делаете с вашими переменными, и компилятор/интерпретатор заботится о том, чтобы обрабатывать связанные с этим задачи низкого уровня. Это простой, простой случай использования переменных с памятью.

Ответ 8

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

В интерпретируемом языке один регистр, если он часто зарезервирован для хранения указателя на структуру данных ( "среда" ), которая связывает имена переменных с их текущими значениями.

Ответ 9

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

Поскольку большинство из нас не являются учеными, машинный язык абстрагируется на язык ассемблера. Assemply - очень примитивный язык, который непосредственно контролирует память. Существует очень ограниченное количество команд (push/pop/add/goto), но в итоге они выполняют все, что запрограммировано. В разных машинных архитектурах есть разные версии сборки, но суть в том, что существует несколько десятков регистров памяти (физически в процессоре). В архитектуре x86 они EAX, EBX, ECX, EDX,... Они содержат данные или которые CPU использует для определения того, что делать дальше. Процессор может делать только одно дело за раз, и он использует эти регистры, чтобы выяснить, что делать дальше. Кажется, что компьютеры могут делать много вещей одновременно, потому что процессор может обрабатывать эти инструкции очень быстро - (миллионы/миллиарды инструкций в секунду). Конечно, многоядерные процессоры усложняют ситуацию, но не идут туда...

Поскольку большинство из нас недостаточно интеллектуальны или достаточно точны, чтобы программировать в сборке, где вы можете легко скомпрометировать систему, сборка дополнительно абстрагируется на язык третьего поколения (3GL) - это ваш C/С++/С#/Java и т.д... Когда вы говорите одному из этих языков, чтобы положить целочисленное значение 5 в переменную, ваши инструкции хранятся в тексте; ассемблер компилирует ваш текст в файл сборки (исполняемый файл); когда программа выполняется, программа и ее команды ставятся в очередь CPU, когда это время показа для этой конкретной строки кода, оно считывается в регистре CPU и обрабатывается.

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

Ответ 10

Существует немаловажный недостаток, который делает несколько человек, который предполагает, что все переменные хранятся в памяти. Ну, если вы не считаете регистры процессора как память, тогда это будет не совсем правильно. Некоторые компиляторы оптимизируют сгенерированный код, и если они могут хранить переменную, хранящуюся в регистре, то некоторые компиляторы будут использовать это! Тогда, конечно, есть сложная проблема памяти кучи и стека. Локальные переменные могут быть расположены в обоих! Предпочтительное местоположение будет находиться в стеке, доступ к которому осуществляется чаще, чем куча. Это касается почти всех локальных переменных. Глобальные переменные часто являются частью сегмента данных конечного исполняемого файла и, как правило, становятся частью кучи, хотя вы не можете освободить эти глобальные области памяти. Но куча часто используется для распределения "на лету" новых блоков памяти, выделяя для них память.

Но с глобальными переменными код точно знает, где они находятся, и таким образом записывает их точное местоположение в коде. (Ну, их расположение от начала сегмента данных в любом случае.) Регистровые переменные расположены в ЦП, и компилятор точно знает, какой регистр, который также просто передается в код. Переменные стека расположены со смещением от текущего указателя стека. Указатель стека будет увеличиваться и уменьшаться все время, в зависимости от количества уровней процедур, вызывающих другие процедуры. Только значения кучи сложны. Когда приложение должно хранить данные в куче, для его сохранения требуется вторая переменная, иначе она может потерять трек. Эта вторая переменная называется указателем и находится в виде глобальных данных или как часть стека. (Или, в редких случаях, в регистры процессора.)

О, это даже немного сложнее, чем это, но уже я вижу, как некоторые глаза катятся из-за этой избыточной информации.: -)

Ответ 11

Подумайте о памяти как ящике, в который вы решите, как ее делить в соответствии с вашими спонтанными потребностями.

Когда вы объявляете переменную типа integer или любого другого типа, компилятор или интерпретатор (в зависимости от того, который выбрал) выделяет адрес памяти в своем сегменте данных (регистр DS на ассемблере) и резервирует определенное количество следующих адресов в зависимости от вашей длины типа в бит.

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

В момент компиляции, если вы ссылаетесь на свою переменную, сгенерированный код ассемблера заменит его своим адресом DS. Итак, когда вы получаете значение переменной C, процессор запрашивает адрес D003F8AC и извлекает его.

Надеюсь, это поможет, так как у вас уже есть много ответов.: -)