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

В чем разница между дальними указателями и ближайшими указателями?

Может ли кто-нибудь сказать мне разницу между указателями far и указателями near в C?

4b9b3361

Ответ 1

В 16-разрядной архитектуре с разбивкой по сегментам x86 четыре регистра используются для обозначения соответствующих сегментов:

  • DS → сегмент данных
  • CS → сегмент кода
  • SS → сегмент стека
  • ES → дополнительный сегмент

Логический адрес этой архитектуры написан segment:offset. Теперь, чтобы ответить на вопрос:

  • Рядом с указателями ссылаются (как смещение) на текущий сегмент.

  • Дальнейшие указатели используют информацию о сегментах и ​​смещение, чтобы указать сегменты. Поэтому для их использования DS или CS необходимо изменить на указанное значение, память будет разыменована, а затем восстановлено исходное значение DS/CS. Обратите внимание, что арифметика указателей на них не изменяет сегментную часть указателя, поэтому переполнение смещения просто обернет его.

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

В 32-битных и 64-разрядных архитектурах модели памяти используют сегменты по-разному или вообще не работают.

Ответ 2

Поскольку никто не упоминал о DOS, давайте забудем о старых компьютерах с DOS-ПК и посмотрим на это с общей точки зрения. Затем, очень упрощенно, это выглядит так:


Любой ЦП имеет шину данных, которая представляет собой максимальный объем данных, которые ЦП может обработать в одной инструкции, т.е. равный размеру его регистров. Ширина шины данных выражается в битах: 8 бит, или 16 бит, или 64 бита и т.д. Отсюда и происходит термин "64-битный ЦП" - он относится к шине данных.

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

Например, если компьютер имеет 65536 байтов адресуемой памяти, вы можете покрыть их 16-битной адресной шиной, 2 ^ 16 = 65536.

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

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

Например, для ЦП с 16-битной шиной данных может быть удобно иметь 16-битную адресную шину. Но тому же компьютеру может потребоваться более 2 ^ 16 = 65536 байт = 64 КБ адресуемой памяти.

В этом случае процессор обычно имеет специальные инструкции (которые немного медленнее), что позволяет ему обращаться к памяти за пределы этих 64 КБ. Например, ЦП может разделить свою большую память на страницы n (также иногда называемые банками, сегментами и другими такими терминами, которые могут означать разные вещи от одного ЦП к другому), где каждая страница занимает 64 КБ. Затем он будет иметь "страничный" регистр, который должен быть установлен первым, прежде чем обращаться к этой расширенной памяти. Точно так же у него будут специальные инструкции при вызове/возврате из подпрограмм в расширенной памяти.

Чтобы компилятор C генерировал правильные инструкции CPU при работе с такой расширенной памятью, были изобретены нестандартные ключевые слова near и far. Нестандартные, как в, они не определены стандартом C, но де-факто они являются отраслевым стандартом, и почти каждый компилятор поддерживает их в некотором роде.

far относится к памяти, расположенной в расширенной памяти, за пределами ширины адресной шины. Поскольку это относится к адресам, чаще всего вы используете его при объявлении указателей. Например: int * far x; означает "дай мне указатель, который указывает на расширенную память". И тогда компилятор будет знать, что он должен генерировать специальные инструкции, необходимые для доступа к такой памяти. Точно так же указатели функций, которые используют far, будут генерировать специальные инструкции для перехода в/из расширенной памяти. Если бы вы не использовали far, вы бы получили указатель на обычную адресуемую память и в итоге указали бы на что-то совершенно другое.

near в основном включен для согласованности с far; это относится к чему-либо в адресуемой памяти, как эквивалентно обычному указателю. Таким образом, это в основном бесполезное ключевое слово, за исключением редких случаев, когда вы хотите убедиться, что код помещен в стандартную адресуемую память. Затем вы можете явно пометить что-то как near. Наиболее типичным случаем является низкоуровневое аппаратное программирование, когда вы пишете процедуры обслуживания прерываний. Они вызываются аппаратно из вектора прерывания с фиксированной шириной, которая равна ширине адресной шины. Это означает, что подпрограмма обработки прерываний должна находиться в стандартной адресуемой памяти.


Наиболее известное использование far и near - это, возможно, упомянутый старый ПК с MS DOS, который в настоящее время считается довольно древним и поэтому представляет небольшой интерес.

Но эти ключевые слова существуют и на более современных процессорах! Это особенно заметно во встроенных системах, где они существуют практически для каждого семейства микроконтроллеров с 8 и 16 битами, представленных на рынке, поскольку эти микроконтроллеры обычно имеют ширину адресной шины 16 бит, но иногда больше 64 КБ памяти.

Всякий раз, когда у вас есть ЦП, где вам необходимо адресовать память сверх ширины адресной шины, вам понадобятся far и near. Как правило, такие решения не одобряются, поскольку программировать на них довольно сложно и всегда учитывать расширенную память.

Одной из основных причин, по которой возникла тенденция к разработке 64-разрядного ПК, было то, что 32-разрядные ПК достигли точки, когда их использование памяти начало достигать предела адресной шины: они могли адресовать только 4 ГБ ОЗУ. 2 ^ 32 = 4,29 млрд байт = 4 ГБ. Чтобы можно было использовать больше оперативной памяти, можно было либо прибегнуть к какому-нибудь обременительному решению с расширенной памятью, как в дни DOS, либо расширить компьютеры, включая их адресную шину, до 64 бит.

Ответ 3

Дальние и ближние указатели использовались на старых платформах, таких как DOS.

Я не думаю, что они актуальны на современных платформах. Но вы можете узнать о них здесь и здесь (как указано другими ответами). В основном, указатель far - это способ расширения адресной памяти на компьютере. I.E., адресует более 64 тыс. Памяти на 16-битной платформе.

Ответ 4

Указатель в основном содержит адреса. Как мы все знаем, управление памятью Intel разделено на 4 сегмента. Поэтому, когда адрес, на который указывает указатель, находится внутри одного и того же сегмента, то он является ближайшим указателем и поэтому для смещения требуется всего 2 байта. С другой стороны, когда указатель указывает на адрес, который находится вне сегмента (что означает в другом сегменте), то этот указатель является дальним указателем. Он состоит из 4 байтов: два для сегмента и два для смещения.

Ответ 5

Четыре регистра используются для обозначения четырех сегментов в 16-разрядной архитектуре сегментированной памяти x86. DS (сегмент данных), CS (сегмент кода), SS (сегмент стека) и ES (дополнительный сегмент). Логическим адресом на этой платформе является записанный сегмент: offset, в шестнадцатеричном формате.

Рядом с указателями ссылаются (как смещение) на текущий сегмент.

Дальнейшие указатели используют информацию о сегментах и ​​смещение, чтобы указать сегменты. Поэтому для их использования DS или CS необходимо изменить на указанное значение, память будет разыменована, а затем восстановлено исходное значение DS/CS. Обратите внимание, что арифметика указателей на них не изменяет сегментную часть указателя, поэтому переполнение смещения просто обернет его.

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

В 32-битных и 64-разрядных архитектурах модели памяти используют сегменты по-разному или вообще не работают.

Ответ 6

Ну, в DOS это было забавно иметь дело с регистрами. И сегменты. Все о максимальных возможностях подсчета ОЗУ.

Сегодня это почти не имеет значения. Все, что вам нужно прочитать, - это разница между виртуальным/пользовательским пространством и ядром.

Так как win nt4 (когда они украли идеи из * nix), программисты Microsoft начали использовать то, что называлось пространствами памяти пользователя/ядра. И с тех пор избегал прямого доступа к физическим контроллерам. С тех пор проблема была решена и с прямым доступом к сегментам памяти. - Все стало R/W через ОС.

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

И если вам все еще нужно использовать CS (сегмент кода)/DS (сегмент данных) в DOS. Посмотрите на них:

https://en.wikipedia.org/wiki/Intel_Memory_Model http://www.digitalmars.com/ctg/ctgMemoryModel.html

Я хотел бы указать на идеальный ответ ниже.. от Lundin. Я был слишком ленив, чтобы правильно ответить. Лундин дал очень подробное и разумное объяснение "большие пальцы"!