Как это знает, где мое значение находится в памяти?

Я думаю, что ошибки раскладки клавиатуры 13 дюймов серии 9 являются фатальными, хотя серия 9 15 дюймов является такой уникальной и тонкой машиной, она, вероятно, продаст как hotcakes несмотря на проблемы...

33
задан MPelletier 30 April 2012 в 00:51
поделиться

11 ответов

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

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

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

9
ответ дан 27 November 2019 в 18:30
поделиться

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

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

13
ответ дан 27 November 2019 в 18:30
поделиться

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

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

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

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

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

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

6
ответ дан 27 November 2019 в 18:30
поделиться

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

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

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

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

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

6
ответ дан 27 November 2019 в 18:30
поделиться

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

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

Например,

ADD [1A56], 15

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

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

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

4
ответ дан 27 November 2019 в 18:30
поделиться

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

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

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

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

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

3
ответ дан 27 November 2019 в 18:30
поделиться

Вам следует изучить указатели.

http://home.netcom.com/~tjensen/ptr/ch1x.htm

1
ответ дан 27 November 2019 в 18:30
поделиться

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

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

1
ответ дан 27 November 2019 в 18:30
поделиться

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

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

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

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

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

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

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

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

1
ответ дан 27 November 2019 в 18:30
поделиться

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

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

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

1
ответ дан 27 November 2019 в 18:30
поделиться

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

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

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

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

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

1
ответ дан 27 November 2019 в 18:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: