it-roy-ru.com

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

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

44
Madhan

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

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

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

  • Ближайшие указатели относятся (как смещение) к текущему сегменту.

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

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

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

42
Michael Foukarakis

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


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

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

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

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

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

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

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

Чтобы компилятор C генерировал правильные инструкции ЦП при работе с такой расширенной памятью, были изобретены нестандартные ключевые слова 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 бит. 

One of the main reasons why there was a Push to develop the 64 bit PC, was actually that the 32 bit PCs had come to the point where their memory usage was starting to hit the address bus limit: they could only address 4Gb of RAM. 2^32 = 4,29 billion bytes = 4Gb. In order to enable the use of more RAM, the options were then either to resort to some burdensome extended memory solution like in the DOS days, or to expand the computers, including their address bus, to 64 bits.

32
Lundin

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

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

22
Pablo Santa Cruz

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

4
aman singh bhandari

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

Ближайшие указатели относятся (как смещение) к текущему сегменту.

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

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

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

0
dharam raj

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

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

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

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

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

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

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

0
Oskars Lusis