1

我在 C 程序中找到了这个声明

 char huge * far *p;

说明:p 是大指针,*p 是远指针,**p 是 char 类型的数据变量。

请更详细地解释声明。

PS:我不是在这里询问大指针或远指针。我是编程新手

4

4 回答 4

2

**p是字符。现在指向该字符地址的指针将具有值 & (**p)。同样,如果您想获取指向此指针的指针,则 next 将是 &(*p) 并且结果将仅为 p。

如果你从右到左阅读下面的句子,你会明白的

p 是巨大的指针,*p 是远指针,**p 是 char 类型的数据变量。

简而言之,Intel x86 芯片上的虚拟地址有两个组成部分——选择器和偏移量。选择器是基地址表 [2] 的索引,偏移量被添加到该基地址上。这旨在让处理器访问 20 位(在 8086/8、186 上)、30 位(286)或 46 位(386 及更高版本)虚拟地址空间,而无需那么大的寄存器。

'far' 指针有一个明确的选择器。但是,当您对它们进行指针运算时,选择器不会被修改。

'huge' 指针有一个明确的选择器。当您对它们进行指针运算时,尽管选择器可以更改。

于 2013-06-05T08:22:50.050 回答
2

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 指向什么,都指向一个字符。

于 2013-06-05T07:40:56.457 回答
1

回到 8086 的 16 位时代,它会声明一个 32 位指针,指向一个“规范化”的 32 位指针,指向 char(或其数组的第一个)。

存在差异是因为 32 位指针由段号和该段之间的偏移量组成,并且段重叠(这意味着两个不同的指针可以指向相同的物理地址;例如:0x1200:10000x1300: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;
}

好处是可以像使用平坦的内存一样使用内存,而不必担心段和偏移量。

于 2013-06-05T08:00:21.513 回答
0

澄清其他答案:

far关键字是非标准 C,但它不仅仅是古代 PC 时代的一个过时的扩展。今天,有许多现代 8 位和 16 位 CPU 使用“分组”内存将可寻址内存量扩展到 65k 以上。通常,他们使用一个特殊的寄存器来选择一个内存库,有效地以 24 位地址结束。市场上所有 RAM+闪存 > 64kb 的小型微控制器都使用此类功能。

于 2013-06-05T09:03:05.600 回答