编译器如何理解指针和数组的声明

How does compiler understand the declaration of pointers and arrays

当我对指向数组的指针和指针数组感到困惑时,我想到了这个问题,尽管我现在已经想出了如何从字面上区分它们。

但我仍然对编译器如何理解指针声明感到困惑。比如有没有int*这样的类型?

int *p;   // a common pointer declaration

具体来说,编译器是如何理解前一句的?先把p当作一个指针,然后发现指向的对象是int?或者发现用户声明了一个名为 p?

的指向 int int* 的指针

面对指向数组的指针时,我更困惑。

int (*p)[4]   //a pointer to an array of int[4]

这个怎么理解?编译器是否将其视为 int[4] *pint[4] 像我们在容器中所做的那样像新类型一样工作)?以下案例中的类似问题。

int *p[4]    //an array-of-pointers

由于 [] 先于 *,编译器是否首先理解 p[4] 并将 p 视为数组(具有未知元素类型),然后指定元素输入 int*?

声明的解析可以在当前标准的第6.7.6节中找到。它太大了,无法完整介绍,但简而言之,关于 p 类型的规则以 inductive 方式列出。在这些规则中,T 是普通类型(没有 pointers/arrays 等),D 是声明符:

  1. T * D的定义是,如果T D中的D的类型是"something of/to T",那么[=12的类型=] 是 "something of pointer to T".

  2. T D[N](其中 N 可以是空白或其他各种东西)被定义为表示如果 T DD 的类型将是 "something of T",那么D的类型就是"something of/to array (of dimension N) of T".

因此您可以看到每个规则都会修改先前应用该规则的结果,直到我们深入到归纳的 "end",这发生在 D 是普通标识符时。

此外,T ( D ) 表示 T D 除了强制解析。

一些消息来源将声明描述为正在阅读 "inside out",虽然这个归纳链实际上发生了 "outside in",但您需要进入然后回溯您的结果。作为人类,我们可能被教导阅读的方式与语言定义不同,尽管最终结果是一样的。


要使用您的示例之一,int *p[4]:

  • 规则 1 - 其形式为 T * D,其中 T = intD = p[4]。由于 T D 将是 "array[4] of int"(见下文),因此 T * D 是 "array[4] of pointer to int".

这一步我们分析了int q[4]:

  • 规则 2 - 其形式为 T D[N],其中 T = intD = q。这是 "end case" 因为 D 是一个普通标识符,所以这一步 q 的类型是 "array[4] of int".

再比如,int (*p)[4]:

  • 规则 2 - 这是 T D[N] 的形式,其中 T = int,并且 D = (*p)。由于 T D 将是 "pointer to int",因此 T D[4] 是 "pointer to array[4] of int"。