简体   繁体   English

说明C中的变量声明

[英]Explain variable declaration in C

I found this declaration in a C program 我在C程序中找到了这个声明

 char huge * far *p;

Explanation: p is huge pointer, *p is far pointer and **p is char type data variable. 说明:p是巨大的指针,* p是远指针,而** p是char类型的数据变量。

Please explain declaration in more detail. 请更详细地说明声明。

PS: I'm not asking about huge or far pointer here. PS:我不是在问巨大或遥远的指针。 I'm a newbie to programming 我是编程的新手

Huge and far pointers are not part of standard C. They are borland extensions to the C language for managing segmented memory in DOS and Windows 16/32bit. 巨大指针和远指针都不是标准C的一部分。它们是C语言的borland扩展,用于管理DOS和Windows 16 / 32bit中的分段内存。 Functionally, what the declaration says is **p is a char. 从功能上讲,声明所说的** p是一个字符。 That means "dereference p to get a pointer to char, dereference that to get a char" 这意味着“取消引用p以获取指向char的指针,取消引用以获取char的指针”

In order to understand C pointer declarator semantics try this expression instead: 为了理解C指针声明符的语义,请尝试以下表达式:

int* p; 

It means p is a pointer to int. 这意味着p是一个指向int的指针。 (hint: read from right to left) (提示:从右到左阅读)

int* const p;

This means p is a const pointer to int. 这意味着p是指向int的const指针。 (so you can't change the value of p) Here's a proof of that: (因此您不能更改p的值)这是一个证明:

p= 42; // error: assignment of read-only variable ‘p’

Another example: 另一个例子:

int* const* lol; 

This means lol is a pointer to const pointer to int. 这意味着lol是指向int的const指针。 So the pointer which lol points at cannot point at another int. 因此,lol指向的指针不能指向另一个int。

lol= &p; // and yes, p cannot be reassigned, so we are correct.

In most cases reading from right to left makes sense. 在大多数情况下,从右到左阅读是有意义的。 Now read the expression in question from right to left: 现在从右到左阅读有问题的表达式:

char huge * far *p;

Now the huge and far are just behaviour specifiers for pointers created by borland. 现在,巨大的和仅是borland创建的指针的行为说明符。 What it actually means is 真正的意思是

char** p;

"p is a pointer to pointer to char" “ p是指向char的指针”

That means whatever p points to, points to a char. 这意味着p指向的任何字符都指向一个字符。

**p is character.Now a pointer pointing to address of this character will have value & (**p). ** p 是字符,现在指向该字符地址的指针将具有值& (** p)。 Again if you want to take pointer to this pointer then next will be &(*p) and result will be p only. 同样,如果您要使用指向此指针的指针,则下一个将为&(* p),结果将仅为p。

If you read below sentence from right to left, you will get it all 如果您从右到左阅读下面的句子,您将一无所有

p is huge pointer, *p is far pointer and **p is char type data variable. p是大指针,* p是远指针,** p是char类型数据变量。

In a nutshell virtual addresses on an Intel x86 chip have two components - a selector and an offset. 简而言之,Intel x86芯片上的虚拟地址包含两个组件-选择器和偏移量。 The selector is an index into a table of base addresses [2] and the offset is added onto that base address. 选择器是基地址表[2]的索引,并将偏移量添加到该基地址。 This was designed to let the processor access 20 bit (on a 8086/8, 186), 30 bit (286) or 46 bit (386 and later) virtual address spaces without needing registers that big. 它旨在让处理器访问20位(在8086 / 8、186上),30位(286)或46位(386及更高版本)的虚拟地址空间,而无需那么大的寄存器。

'far' pointers have an explicit selector. “远”指针具有显式选择器。 However when you do pointer arithmetic on them the selector isn't modified. 但是,当您对它们执行指针算术运算时,不会修改选择器。

'huge' pointers have an explicit selector. “巨大”指针具有显式选择器。 When you do pointer arithmetic on them though the selector can change. 当您对它们进行指针算术运算时,选择器可以更改。

Back in the 16-bit days on 8086, it would have declared a 32-bit pointer to a "normalized" 32-bit pointer to char (or to the first of an array thereof). 早在8086年的16位日子里,它就已经声明了指向char的“规范化” 32位指针(或其数组的第一个指针)的32位指针。

The difference exists because 32-bit pointers were composed of a segment number and offset between that segment, and segments overlapped (which meant two different pointers could point to the same physical address; example: 0x1200:1000 and 0x1300:0000 ). 之所以存在差异,是因为32位指针由一个段号和该段之间的偏移量组成,并且段重叠(这意味着两个不同的指针可以指向同一物理地址;例如: 0x1200:10000x1300:0000 )。 The huge qualifier forced a normalization using the highest segment number (and therefore, the lowest possible offset). huge限定符使用最高的段号(因此,可能的偏移量最小)强制进行归一化。

However, this normalization had a cost performance-wise, because after each operation that modified a pointer, the compiler had to automatically insert a code like this: 但是,这种标准化在性能上具有成本效益,因为在每次修改指针的操作之后,编译器必须自动插入如下代码:

ptr = normalize(ptr);

with: 与:

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;
}

The upside was the advantage of using your memory like it was flat, without worrying about segments and offsets. 好处是可以像平放一样使用内存,而不必担心分段和偏移量的优势。

Clarification to the other answers: 澄清其他答案:

The far keyword is non-standard C, but it is not just an old obsolete extension from ancient PC days. far关键字是非标准的C,但它不仅仅是来自古代PC时代的旧版本。 Today, there are many modern 8 and 16 bit CPUs that uses "banked" memory to extend the amount of addressable memory beyond 65k. 如今,有许多现代的8位和16位CPU使用“存储”内存将可寻址内存量扩展到65k以上。 Typically they use a special register to pick a memory bank, effectively ending up with 24-bit addresses. 通常,它们使用特殊的寄存器来选择存储区,有效地以24位地址结尾。 All small microcontrollers on the market with RAM+flash memory > 64kb use such features. 市场上所有具有大于64kb RAM +闪存的小型微控制器都使用这种功能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM