在一条指令中声明多个指针的运算符优先级

Operator Precedence in declaring more pointers in one instruction

我想了解为什么在同一行上声明更多具有相同数据类型的指针时必须在每个标识符前添加一个星号。

Here 是我阅读的地方


可能引起您注意的另一件事是:

int * p1, * p2;

这声明了上一个示例中使用的两个指针。但是请注意,每个指针都有一个星号 (*),以便两者都具有类型 int*(指向 int 的指针)。 由于优先规则,这是必需的。请注意,如果代码是:

int * p1, p2;

p1 确实是 int* 类型,但 p2 是 int 类型。为此,空格根本无关紧要。但无论如何,对于大多数有兴趣在每个语句中声明多个指针的指针用户来说,只需记住为每个指针加上一个星号就足够了。甚至更好:对每个变量使用不同的语句。


operator precedence

问题:这里用的是什么规则,这是什么优先级?它是关于逗号还是星号?想不通了。

本身没有优先规则;相反,它是一条规则,表示 int 部分适用于所有变量,而 * 仅适用于紧随其后的部分。

规则的通用版本是声明中的所有 说明符 适用于声明的每个实体。说明符包括 constexprstatic 等关键字,以及 int 和用户定义的类型名称等表示类型的关键字。 *& 等运算符修改类型说明符以创建更复杂的类型,但是,一次仅适用于一个实体。

这里不涉及运算符优先级。事实上也没有运营商。运算符对表达式进行操作,但这是一个声明。

声明的语法是:

T D1, D2, D3, D4;

等同于:

T D1; T D2; T D3; T D4;

其中:

  • T声明说明符:没有符号,只有关键字(例如 intconststatic) and/or 类型定义名称。
  • Dn 是一个 声明符 ,即一个标识符(变量的名称)可能带有 *[](parameter-list) 或以各种方式附加的分组括号。

在您的第一个示例中,Tint,声明符是 *p1*p2

没有任何优先规则。一个简单声明的语法看起来像

decl-specifier-seq init-declarator-listopt ; 

符号 * 属于声明符,不属于 decl-specidier-seq,例如类型说明符 int.

所以你可以重写声明

int * p1, * p2;

喜欢

int ( * p1 ), ( * p2 );

其中 ( *p1 ) 和 ( *p2 ) 是标号(虽然在这种情况下括号是多余的)

你可能不会写例如

( int * ) p1, p2;

编译器会报错。

声明更复杂的类型时需要括号。例如,让我们声明一个指向数组的指针

int ( *p )[N];

其中 N 是某个常数。

因此您可以将声明符括在括号中。

让我们考虑一个更复杂的声明:returns 一个指向函数的指针并以另一个函数作为参数的函数

void ( *f( int cmp( const void *, const void * ) )( int *a );

至于优先级,则构建声明符的规则在语法中描述了它们

例如

如果你会写

int * a[10];

那么它是一个包含 10 个元素的数组,类型为 int *

但是如果你会写

int ( *a[10] ); 

然后它是一个包含 10 个指向 int.

类型对象的指针的数组

如果你会写

int ( *a )[10];

那么它是一个指向10个整数数组的指针。

考虑到 typedef 也是一个声明说明符。

例如这个 typedef

typedef int *intPtr;

你可以重写

int typedef *intPtr;

甚至喜欢

int typedef ( *intPtr );

再来一个声明的例子。让我们考虑一个多维数组。 In 可以声明为

int ( ( ( a )[N1] )[N2] );

不过括号又是多余的。但是,它们可以帮助理解数组如何隐式转换为指向表达式中第一个元素的指针。

例如,如果你有一个数组

int a[N1][N2];

然后要获得指向其第一个元素的指针声明,您可以重写声明,例如

int ( a[N1] )[N2];

现在用 a[N1] 代替 *a(或者例如 *p)。

int ( *p )[N2] = a;