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

Operator Precedence in declaring more pointers in one instruction

本文关键字:指针 优先级 运算符 声明 指令 一个      更新时间:2023-10-16

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

这是我阅读的地方


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

整数 * P1, * P2;

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

整数 * P1, P2;

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


运算符优先级

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

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

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 是某个常数。

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

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

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 也是一个 decl-specifier。

所以例如这个类型定义

typedef int *intPtr;

你可以像这样重写

int typedef *intPtr;

甚至喜欢

int typedef ( *intPtr );

再举一个声明的例子。让我们考虑一个多维数组。在可以声明为类似

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

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

例如,如果你有一个数组

int a[N1][N2];

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

int ( a[N1] )[N2];

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

int ( *p )[N2] = a;

本身没有优先规则;相反,它是一条规则,int部分适用于所有变量,而*只适用于它后面的变量。

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

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

声明的语法是:

T D1, D2, D3, D4;

表示与以下相同:

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

哪里:

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

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