我在 C 程序中找到了这个声明
char huge * far *p;
说明:p 是大指针,*p 是远指针,**p 是 char 类型的数据变量。
请更详细地解释声明。
PS:我不是在这里询问大指针或远指针。我是编程新手
我在 C 程序中找到了这个声明
char huge * far *p;
说明:p 是大指针,*p 是远指针,**p 是 char 类型的数据变量。
请更详细地解释声明。
PS:我不是在这里询问大指针或远指针。我是编程新手
**p是字符。现在指向该字符地址的指针将具有值 & (**p)。同样,如果您想获取指向此指针的指针,则 next 将是 &(*p) 并且结果将仅为 p。
如果你从右到左阅读下面的句子,你会明白的
p 是巨大的指针,*p 是远指针,**p 是 char 类型的数据变量。
简而言之,Intel x86 芯片上的虚拟地址有两个组成部分——选择器和偏移量。选择器是基地址表 [2] 的索引,偏移量被添加到该基地址上。这旨在让处理器访问 20 位(在 8086/8、186 上)、30 位(286)或 46 位(386 及更高版本)虚拟地址空间,而无需那么大的寄存器。
'far' 指针有一个明确的选择器。但是,当您对它们进行指针运算时,选择器不会被修改。
'huge' 指针有一个明确的选择器。当您对它们进行指针运算时,尽管选择器可以更改。
Huge 和 far 指针不是标准 C 的一部分。它们是 C 语言的 borland 扩展,用于在 DOS 和 Windows 16/32 位中管理分段内存。从功能上讲,声明中所说的 **p 是一个字符。这意味着“取消引用 p 以获取指向 char 的指针,取消引用以获取 char”
为了理解 C 指针声明符语义,请尝试使用以下表达式:
int* p;
这意味着 p 是一个指向 int 的指针。(提示:从右到左阅读)
int* const p;
这意味着 p 是一个指向 int 的 const 指针。(所以你不能改变 p 的值)这是一个证明:
p= 42; // error: assignment of read-only variable ‘p’
另一个例子:
int* const* lol;
这意味着 lol 是一个指向 const 的指针,指向 int 的指针。所以lol指向的指针不能指向另一个int。
lol= &p; // and yes, p cannot be reassigned, so we are correct.
在大多数情况下,从右向左阅读是有意义的。现在从右到左阅读有问题的表达式:
char huge * far *p;
现在 huge 和 far 只是 borland 创建的指针的行为说明符。它的实际意思是
char** p;
“p 是指向 char 的指针”
这意味着无论 p 指向什么,都指向一个字符。
回到 8086 的 16 位时代,它会声明一个 32 位指针,指向一个“规范化”的 32 位指针,指向 char(或其数组的第一个)。
存在差异是因为 32 位指针由段号和该段之间的偏移量组成,并且段重叠(这意味着两个不同的指针可以指向相同的物理地址;例如:0x1200:1000
和0x1300:0000
)。限定符强制使用huge
最高段号(因此,尽可能低的偏移量)进行规范化。
但是,这种规范化在性能方面具有成本效益,因为在每次修改指针的操作之后,编译器必须自动插入如下代码:
ptr = normalize(ptr);
和:
void huge * normalize(void huge *input)
{
unsigned long input2 = (unsigned long)input;
unsigned short segment = input >> 16;
unsigned short offset = (unsigned short)input;
segment += (offset >> 4);
offset &= 0x000F;
return ((unsigned long)segment) << 16 | offset;
}
好处是可以像使用平坦的内存一样使用内存,而不必担心段和偏移量。
澄清其他答案:
far
关键字是非标准 C,但它不仅仅是古代 PC 时代的一个过时的扩展。今天,有许多现代 8 位和 16 位 CPU 使用“分组”内存将可寻址内存量扩展到 65k 以上。通常,他们使用一个特殊的寄存器来选择一个内存库,有效地以 24 位地址结束。市场上所有 RAM+闪存 > 64kb 的小型微控制器都使用此类功能。