解释复杂声明符

可以将任何声明符括在圆括号中以指定“复杂声明符”的特殊解释。复杂声明符是由多个数组、指针或函数修饰符限定的标识符。 您可以将数组、指针和函数修饰符的各种组合应用于单个标识符。 通常 typedef 可用来简化声明。 请参阅 Typedef 声明

在解释复杂声明符时,方括号和圆括号(即,标识符右侧的修饰符)优先于星号(即,标识符左侧的修饰符)。 方括号和圆括号具有相同的优先级并且都是从左到右关联。 在完全解释声明符之后,将应用类型说明符以作为最后一步。 通过使用圆括号,您可以重写默认关联顺序和强制实施特定解释。 但是,绝不要单独在标识符名称两边使用圆括号。 这可能会被错误解释为参数列表。

解释复杂声明符的一个简单方法是通过下列 4 个步骤“从里到外”地读取它们:

  1. 从标识符开始并直接查找方括号或圆括号(如果有)的右侧。

  2. 解释这些方括号或圆括号,然后查找星号的左侧。

  3. 如果在任何阶段遇到一个右圆括号,请返回并将规则 1 和 2 应用于圆括号内的所有内容。

  4. 应用类型说明符。

    char *( *(*var)() )[10];
     ^   ^  ^ ^ ^   ^    ^
     7   6  4 2 1   3    5
    

在此示例中,步骤是按顺序编号的,并且可以按如下方式解释:

  1. 标识符 var 声明为

  2. 指向以下内容的指针

  3. 返回以下内容的函数

  4. 指向以下内容的指针

  5. 包含 10 个元素的数组,这些元素分别为

  6. 指向以下内容的指针

  7. char 值。

示例

以下示例阐释了其他复杂声明并演示了圆括号如何影响声明的含义。

int *var[5]; /* Array of pointers to int values */

数组修饰符的优先级高于指针修饰符,因此,var 将声明为数组。 指针修饰符将应用于数组元素的类型;因此,数组元素是指向 int 值的指针。

int (*var)[5]; /* Pointer to array of int values */

在对 var 的此声明中,圆括号为指针修饰符赋予了高于数组修饰符的优先级,并且 var 被声明为指向包含 5 个 int 值的数组的指针。

long *var( long, long ); /* Function returning pointer to long */

函数修饰符的优先级也高于指针修饰符,因此对 var 的此声明将 var 声明为返回指向 long 值的指针的函数。 此函数被声明为接受两个 long 值作为参数。

long (*var)( long, long ); /* Pointer to function returning long */

此示例与前一个示例类似。 括号赋予指针修饰符比函数修饰符更高的优先级,并且 var 被声明为指向返回 long 值的函数的指针。 同样,此函数接受两个 long 参数。

struct both       /* Array of pointers to functions */
{                 /*   returning structures         */
    int a;
    char b;
} ( *var[5] )( struct both, struct both );

数组的元素不能是函数,但此声明演示了如何将指针数组声明为函数。 在此示例中,var 被声明为包含 5 个指向函数(返回具有两个成员的结构)的指针的数组。 函数的参数被声明为具有同一结构类型 both 的两个结构。 请注意,*var[5] 两边需要圆括号。 如果没有它们,声明将是对声明函数数组的非法尝试,如下所示:

/* ILLEGAL */
struct both *var[5](struct both, struct both);

以下语句声明指针的数组。

unsigned int *(* const *name[5][10] ) ( void );

name 数组具有组织在一个多维数组中的 50 个元素。 这些元素是指向常量指针的指针。 此常量指针指向没有参数并返回指向无符号类型的指针的函数。

下一个示例是函数,此函数返回指向包含三个 double 值的数组的指针。

double ( *var( double (*)[3] ) )[3];

在此声明中,函数将返回指向数组的指针,因为返回数组的函数是非法的。 在此处,var 被声明为函数,此函数返回指向包含三个 double 值的数组的指针。 函数 var 将采用一个参数。 与返回值一样,此参数是指向包含三个 double 值的数组的指针。 参数类型由一个复杂 abstract-declarator 给定。 参数类型中星号两边的括号是必需的;如果没有括号,参数类型就是包含三个指向 double 值的指针的数组。 有关抽象声明符的讨论和示例,请参阅抽象声明符

union sign         /* Array of arrays of pointers */
{                  /* to pointers to unions       */
     int x;
     unsigned y;
} **var[5][5];

如上面的示例所示,指针可以指向另一个指针,数组可包含数组作为元素。 这里的 var 是一个包含五个元素的数组。 每个元素都是一个五元素指针数组,这些指针指向指向具有两个成员的联合的指针。

union sign *(*var[5])[5]; /* Array of pointers to arrays
                             of pointers to unions        */

此示例演示圆括号的放置如何更改声明的含义。 在此示例中,var 是一个五元素指针数组,这些指针指向联合的五元素指针数组。 有关如何使用 typedef 避免复杂声明的示例,请参阅 Typedef 声明

请参阅

声明和类型