что предназначено нормализацией в огромных указателях

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

donot дают мне следующее или любые подобные ответы:

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

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

Может любой пытаться объяснить это понятие с точки зрения новичков.

Спасибо, Rahamath

6
задан Donal Fellows 20 May 2010 в 20:39
поделиться

3 ответа

Вначале 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

Разница между далеким и огромным указателем не в нормализации, вы можете иметь ненормализованный огромный указатель , это абсолютно разрешено. Разница заключается в коде, генерируемом при выполнении арифметических операций с указателями. С дальними указателями при увеличении или добавлении значений к указателю не будет обработки переполнения, и вы сможете обрабатывать только 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 и т. Д.) Не обрабатывали переполнения смещения. Это была причина, по которой было хорошей идеей использовать нормализованные указатели с этими библиотечными функциями, вероятность переполнения смещения для них была ниже.

13
ответ дан 8 December 2019 в 04:51
поделиться

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

linear = segment * 16 + offset;

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

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

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

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

10
ответ дан 8 December 2019 в 04:51
поделиться

Насколько я помню, это примерно так:

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

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

1
ответ дан 8 December 2019 в 04:51
поделиться
Другие вопросы по тегам:

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