我对理解"远"指针和"巨大"指针之间的区别感到很困惑,在谷歌搜索它的所有解决方案,找不到一个.任何人都能解释我两者之间的区别.此外,与巨大指针相关的精确归一化概念是什么.
请不要给我以下或任何类似的答案:
"far指针和一个巨大的指针之间的唯一区别是,一个巨大的指针由编译器规范化.规范化的指针是一个在段中具有尽可能多的地址的指针,这意味着偏移量永远不会大于15只有在对它进行指针运算时,才会对一个巨大的指针进行归一化.当进行赋值时,它不会被归一化.你可以使它被归一化,而不是通过递增然后递减来改变它.偏移量必须小于16.因为段可以表示大于或等于16(例如绝对地址的任何值
0x17
的归一化形式是0001:0001
,虽然远指针可以解决的绝对地址0x17
与0000: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 = 12
位2^12 = 4096
).归一化组合是4096个可能值中唯一一个将偏移的3个高半字节归零的组合.在我们的例子中,它将是:
0x 179B
+0x 0008
---------
=0x 179B8
Run Code Online (Sandbox Code Playgroud)
a far
和huge
指针之间的区别不在规范化中,你可以有非规范化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:0000
ptr2且分段地址为0010:0020
,则简单比较将确定ptr1 != ptr2
即使它们实际指向同一地址.
规范化是将地址转换为表单的过程,这样如果两个非规范化指针引用相同的线性地址,它们都将转换为相同的规范化形式.