что подразумевается под нормализацией в огромных указателях - PullRequest
6 голосов
/ 21 мая 2010

У меня большая путаница в понимании разницы между "дальним" указателем и "огромным" указателем, я искал его в google для решения, не мог найти его. Может кто-нибудь объяснить мне разницу между ними. Кроме того, какова точная концепция нормализации, связанная с огромными указателями.

Пожалуйста, не дайте мне следующие или похожие ответы:

"Единственная разница между дальним указателем и огромным указателем состоит в том, что компилятор нормализует огромный указатель. Нормализованный указатель - это тот, который имеет максимально возможный адрес в сегменте, что означает, что смещение никогда не бывает больше 15. Огромный указатель нормализуется только тогда, когда над ним выполняется арифметика указателя. Он не нормализуется при назначении. Вы можете привести его к нормализации без изменения значения, увеличивая и уменьшая его. Смещение должно быть меньше 16, поскольку сегмент может представлять любое значение, большее или равное 16 (например, абсолютный адрес 0x17 в нормализованной форме будет 0001:0001. Хотя дальний указатель может адресовать абсолютный адрес 0x17 с 0000:0017, это недопустимый огромный (нормализованный) указатель, поскольку смещение больше 0000F.). Огромные указатели также можно увеличивать и уменьшать с помощью арифметических операторов, но поскольку они нормализованы, они не будут переноситься, как дальние указатели. "

Здесь концепция нормализации не очень хорошо объяснена, или, может быть, я не могу ее понять очень хорошо.

Может кто-нибудь попытаться объяснить эту концепцию с точки зрения начинающих.

Спасибо, Rahamath

Ответы [ 3 ]

13 голосов
/ 21 мая 2010

В начале 8086 был расширением 8-битного процессора 8085. 8085 мог адресовать только 65536 байтов с его 16-битной адресной шиной.Когда Intel разработала 8086, они хотели, чтобы программное обеспечение было максимально совместимо со старыми 8-битными процессорами, поэтому они представили концепцию сегментной адресации памяти.Это позволило запустить 8-битное программное обеспечение, чтобы жить в большем диапазоне адресов, не замечая этого.8086 имел 20-битную адресную шину и, таким образом, мог обрабатывать до 1 МБ памяти (2 ^ 20).К сожалению, он не мог обратиться к этой памяти напрямую, для этого ему пришлось использовать регистры сегментов.Реальный адрес был рассчитан путем сложения 16-битного значения сегмента, сдвинутого влево на 4, к 16-битному смещению.

Example:
Segment  0x1234   Offset 0x5678 will give the real address
   0x 1234
  +0x  5678
  ---------
  =0x 179B8

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

   0x 1264               0x 1111
  +0x  5378             +0x  68A8
  ---------             ---------     etc.
  =0x 179B8             =0x 179B8

На самом деле существует 4096возможны различные комбинации из-за 3 перекрывающихся кусков (3*4 = 12 бит, 2^12 = 4096).Нормализованная комбинация является единственной из 4096 возможных значений, которые будут иметь 3 старших куска смещения к нулю.В нашем примере это будет:

   0x 179B
  +0x  0008
  ---------
  =0x 179B8

Разница между far и huge указателем не в нормализации, вы можете иметь ненормализованный указатель huge, это абсолютно допустимо.Разница заключается в коде, генерируемом при выполнении арифметики с указателями.При использовании дальних указателей при увеличении или добавлении значений к указателю обработка переполнения не будет, и вы сможете обрабатывать только 64 КБ памяти.

char far *p = (char far *)0x1000FFFF;
p++;
printf("p=%p\n");

напечатает 1000:0000 Для больших указателей компилятор сгенерирует код, необходимый для обработки переноса.

char huge *p = (char huge *)0x1000FFFF;
p++;
printf("p=%p\n");

выведет 2000:0000

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

Не следует также забывать, что большинство 16-битных компиляторов имели библиотеки, которые не обрабатывали эти случаи правильнодавая иногда глючный софт.Компилятор реального режима Microsoft не обрабатывал огромные указатели на все свои строковые функции.Borland был еще хуже, так как даже функции mem (memcpy, memset и т. Д.) Не обрабатывали переполнения смещения.По этой причине было полезно использовать нормализованные указатели с этими библиотечными функциями, вероятность их переполнения была ниже.

10 голосов
/ 21 мая 2010

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

linear = segment * 16 + offset;

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

0004:0000
0003:0010
0002:0020
0001:0030
0000:0040

Проблема заключается в том, что если у вас есть ptr1 с сегментированным адресом 0100:0000 и ptr2 с сегментированным адресомиз 0010:0020, простое сравнение определит, что ptr1 != ptr2, даже если они фактически указывают на один и тот же адрес.

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

1 голос
/ 21 мая 2010

Насколько я помню, это что-то вроде этого:

  • Ближайшие указатели указывают на память в том же сегменте (что и указатель).
  • Дальние указатели указывают на память в другом сегменте.
  • Огромные указатели позволяют вам указывать на память, которая больше, чем сегмент (так что вы можете иметь блок> 64 КБ и делать арифметику на вашем указателе, и то, что сказал Самуэль).

Если вы новичок, вероятно, лучше забыть, что вы слышали о Near / Far / Huge. Они имеют значение только в старой 16-разрядной модели с сегментированной памятью, которую обычно видели в ранних версиях Intel 80x86. В 32- и 64-битной среде (т. Е. Во всем, начиная с 1994 года), память - это просто большой непрерывный блок, поэтому указатель - это просто указатель (для отдельного приложения).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...