大指针中的规范化是什么意思

wra*_*erm 6 c pointers

我对理解"远"指针和"巨大"指针之间的区别感到很困惑,在谷歌搜索它的所有解决方案,找不到一个.任何人都能解释我两者之间的区别.此外,与巨大指针相关的精确归一化概念是什么.

请不要给我以下或任何类似的答案:

"far指针和一个巨大的指针之间的唯一区别是,一个巨大的指针由编译器规范化.规范化的指针是一个在段中具有尽可能多的地址的指针,这意味着偏移量永远不会大于15只有在对它进行指针运算时,才会对一个巨大的指针进行归一化.当进行赋值时,它不会被归一化.你可以使它被归一化,而不是通过递增然后递减来改变它.偏移量必须小于16.因为段可以表示大于或等于16(例如绝对地址的任何值0x17的归一化形式是0001:0001,虽然远指针可以解决的绝对地址0x170000:0017,这不是有效的巨大(归一化)的指针,因为偏移量大比0000F).巨大的指针也可以使用算术运算符递增和递减,但由于它们被标准化,因此它们不会像远指针那样换行.

这里的归一化概念没有得到很好的解释,或者我可能无法理解它.

任何人都可以从初学者的角度尝试解释这个概念.

谢谢,Rahamath

Pat*_*ter 13

开始时8086是8位处理器8085的扩展.8085只能用16位地址总线寻址65536字节.当英特尔开发8086时,他们希望软件尽可能与旧的8位处理器兼容,因此他们引入了分段存储器寻址的概念.这允许运行8位软件以生活在更大的地址范围内而不会注意到.8086具有20位地址总线,因此可以处理高达1 MB的内存(2 ^ 20).不幸的是,它不能直接解决这个内存,它必须使用段寄存器来做到这一点.通过将向左移位4的16位段值加到16位偏移量来计算实际地址.

Example:
Segment  0x1234   Offset 0x5678 will give the real address
   0x 1234
  +0x  5678
  ---------
  =0x 179B8
Run Code Online (Sandbox Code Playgroud)

正如您将注意到的,此操作不是双射的,这意味着您可以使用其他段和偏移的组合生成实际地址.

   0x 1264               0x 1111
  +0x  5378             +0x  68A8
  ---------             ---------     etc.
  =0x 179B8             =0x 179B8
Run Code Online (Sandbox Code Playgroud)

实际上有4096种不同的组合,因为3个重叠的半字节(3*4 = 122^12 = 4096).归一化组合是4096个可能值中唯一一个将偏移的3个高半字节归零的组合.在我们的例子中,它将是:

   0x 179B
  +0x  0008
  ---------
  =0x 179B8
Run Code Online (Sandbox Code Playgroud)

a farhuge指针之间的区别不在规范化中,你可以有非规范化huge指针,它是绝对允许的.不同之处在于执行指针运算时生成的代码.使用far指针向指针递增或添加值时,将不会有溢出处理,您将只能处理64K的内存.

char far *p = (char far *)0x1000FFFF;
p++;
printf("p=%p\n");
Run Code Online (Sandbox Code Playgroud)

将打印1000:0000 对于巨大的指针,编译器将生成处理结转所需的代码.

char huge *p = (char huge *)0x1000FFFF;
p++;
printf("p=%p\n");
Run Code Online (Sandbox Code Playgroud)

将打印 2000:0000

这意味着在使用远或大指针时必须要小心,因为使用它们的算术成本是不同的.

人们也不应该忘记,大多数16位编译器都有没有正确处理这些情况的库,有时会提供有缺陷的软件.微软实模式编译器没有处理其所有字符串函数的巨大指针.Borland公司甚至因为即使是MEM功能(更糟糕memcpy,memset等)没有处理溢出抵消.这就是为什么使用带有这些库函数的规范化指针是个好主意的原因,偏移溢出的可能性随之降低.


R S*_*hko 10

首先要理解的是如何将分段指针转换为线性地址.对于您的示例,转换是:

linear = segment * 16 + offset;
Run Code Online (Sandbox Code Playgroud)

因此,可以看出,使用不同的段/偏移组合可以表示相同的线性地址.例如,以下段/偏移量组合都指向相同的线性地址:

0004:0000
0003:0010
0002:0020
0001:0030
0000:0040
Run Code Online (Sandbox Code Playgroud)

这样做的问题是,如果ptr1的分段地址为0100:0000ptr2且分段地址为0010:0020,则简单比较将确定ptr1 != ptr2即使它们实际指向同一地址.

规范化是将地址转换为表单的过程,这样如果两个非规范化指针引用相同的线性地址,它们都将转换为相同的规范化形式.