解释复杂声明符Interpreting More Complex Declarators

您可以将任何声明符括在圆括号中以指定“复杂声明符”的特殊解释。You can enclose any declarator in parentheses to specify a particular interpretation of a "complex declarator." 复杂声明符是由多个数组、指针或函数修饰符限定的标识符。A complex declarator is an identifier qualified by more than one array, pointer, or function modifier. 您可以将数组、指针和函数修饰符的各种组合应用于单个标识符。You can apply various combinations of array, pointer, and function modifiers to a single identifier. 通常 typedef 可用来简化声明。Generally typedef may be used to simplify declarations. 请参阅 Typedef 声明See Typedef Declarations.

在解释复杂声明符时,方括号和圆括号(即,标识符右侧的修饰符)优先于星号(即,标识符左侧的修饰符)。In interpreting complex declarators, brackets and parentheses (that is, modifiers to the right of the identifier) take precedence over asterisks (that is, modifiers to the left of the identifier). 方括号和圆括号具有相同的优先级并且都是从左到右关联。Brackets and parentheses have the same precedence and associate from left to right. 在完全解释声明符之后,将应用类型说明符以作为最后一步。After the declarator has been fully interpreted, the type specifier is applied as the last step. 通过使用圆括号,您可以重写默认关联顺序和强制实施特定解释。By using parentheses you can override the default association order and force a particular interpretation. 但是,绝不要单独在标识符名称两边使用圆括号。Never use parentheses, however, around an identifier name by itself. 这可能会被错误解释为参数列表。This could be misinterpreted as a parameter list.

解释复杂声明符的一个简单方法是通过下列 4 个步骤“从里到外”地读取它们:A simple way to interpret complex declarators is to read them "from the inside out," using the following four steps:

  1. 从标识符开始并直接查找方括号或圆括号(如果有)的右侧。Start with the identifier and look directly to the right for brackets or parentheses (if any).

  2. 解释这些方括号或圆括号,然后查找星号的左侧。Interpret these brackets or parentheses, then look to the left for asterisks.

  3. 如果在任何阶段遇到一个右圆括号,请返回并将规则 1 和 2 应用于圆括号内的所有内容。If you encounter a right parenthesis at any stage, go back and apply rules 1 and 2 to everything within the parentheses.

  4. 应用类型说明符。Apply the type specifier.

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

    在此示例中,步骤是按顺序编号的,并且可以按如下方式解释:In this example, the steps are numbered in order and can be interpreted as follows:

  5. 标识符 var 声明为The identifier var is declared as

  6. 指向以下内容的指针a pointer to

  7. 返回以下内容的函数a function returning

  8. 指向以下内容的指针a pointer to

  9. 包含 10 个元素的数组,这些元素分别为an array of 10 elements, which are

  10. 指向以下内容的指针pointers to

  11. char 值。char values.

示例Examples

以下示例阐释了其他复杂声明并演示了圆括号如何影响声明的含义。The following examples illustrate other complex declarations and show how parentheses can affect the meaning of a declaration.

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

数组修饰符的优先级高于指针修饰符,因此,var 将声明为数组。The array modifier has higher priority than the pointer modifier, so var is declared to be an array. 指针修饰符将应用于数组元素的类型;因此,数组元素是指向 int 值的指针。The pointer modifier applies to the type of the array elements; therefore, the array elements are pointers to int values.

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

在对 var 的此声明中,圆括号为指针修饰符赋予了高于数组修饰符的优先级,并且 var 被声明为指向包含 5 个 int 值的数组的指针。In this declaration for var, parentheses give the pointer modifier higher priority than the array modifier, and var is declared to be a pointer to an array of five int values.

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

函数修饰符的优先级也高于指针修饰符,因此对 var 的此声明将 var 声明为返回指向 long 值的指针的函数。Function modifiers also have higher priority than pointer modifiers, so this declaration for var declares var to be a function returning a pointer to a long value. 该函数被声明为采用两个 long 值作为参数。The function is declared to take two long values as arguments.

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

此示例与前一个示例类似。This example is similar to the previous one. 圆括号为指针修饰符赋予了高于函数修饰符的优先级,var 被声明为指向返回 long 值的函数的指针。Parentheses give the pointer modifier higher priority than the function modifier, and var is declared to be a pointer to a function that returns a long value. 同样,该函数采用两个 long 参数。Again, the function takes two long arguments.

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

数组的元素不能是函数,但此声明演示了如何将指针数组声明为函数。The elements of an array cannot be functions, but this declaration demonstrates how to declare an array of pointers to functions instead. 在此示例中,var 被声明为包含 5 个指向函数(返回具有两个成员的结构)的指针的数组。In this example, var is declared to be an array of five pointers to functions that return structures with two members. 函数的参数被声明为具有同一结构类型 both 的两个结构。The arguments to the functions are declared to be two structures with the same structure type, both. 请注意,*var[5] 两边需要圆括号。Note that the parentheses surrounding *var[5] are required. 如果没有它们,声明将是对声明函数数组的非法尝试,如下所示:Without them, the declaration is an illegal attempt to declare an array of functions, as shown below:

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

以下语句声明指针的数组。The following statement declares an array of pointers.

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

name 数组具有组织在一个多维数组中的 50 个元素。The name array has 50 elements organized in a multidimensional array. 这些元素是指向常量指针的指针。The elements are pointers to a pointer that is a constant. 此常量指针指向没有参数并返回指向无符号类型的指针的函数。This constant pointer points to a function that has no parameters and returns a pointer to an unsigned type.

下一个示例是函数,该函数返回指向包含三个 double 值的数组的指针。This next example is a function returning a pointer to an array of three double values.

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

在此声明中,函数将返回指向数组的指针,因为返回数组的函数是非法的。In this declaration, a function returns a pointer to an array, since functions returning arrays are illegal. 在此处,var 被声明为一个函数,该函数返回了指向包含三个 double 值的数组的指针。Here var is declared to be a function returning a pointer to an array of three double values. 函数 var 将采用一个参数。The function var takes one argument. 参数(如返回值)是指向包含三个 double 值的数组的指针。The argument, like the return value, is a pointer to an array of three double values. 参数类型由一个复杂 abstract-declarator 给定。The argument type is given by a complex abstract-declarator. 参数类型中的星号两边需要圆括号;如果没有圆括号,参数类型将是一个包含三个指向 double 值的指针的数组。The parentheses around the asterisk in the argument type are required; without them, the argument type would be an array of three pointers to double values. 有关抽象声明符的讨论和示例,请参阅抽象声明符For a discussion and examples of abstract declarators, see Abstract Declarators.

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

如上面的示例所示,指针可以指向另一个指针,数组可包含数组作为元素。As the above example shows, a pointer can point to another pointer, and an array can contain arrays as elements. 这里的 var 是一个包含五个元素的数组。Here var is an array of five elements. 每个元素都是一个五元素指针数组,这些指针指向指向具有两个成员的联合的指针。Each element is a five-element array of pointers to pointers to unions with two members.

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

此示例演示圆括号的放置如何更改声明的含义。This example shows how the placement of parentheses changes the meaning of the declaration. 在此示例中,var 是一个五元素指针数组,这些指针指向联合的五元素指针数组。In this example, var is a five-element array of pointers to five-element arrays of pointers to unions. 有关如何使用 typedef 避免复杂声明的示例,请参阅 Typedef 声明For examples of how to use typedef to avoid complex declarations, see Typedef Declarations.

另请参阅See Also

声明和类型Declarations and Types