假设我有一个结构
struct s
{
int a;
}
以及像这样的主要功能
int main()
{
struct s s1 = {.a = 10};
struct s *sptr = &s1;
sptr->a--;
printf("%d\n", sptr->a);
s1.a = 10;
--sptr->a;
printf("%d\n", sptr->a);
return 0;
}
输出 :
9
9
按照运算符优先级,->
具有--
相同的优先级和左->右结合性。
如果是sptr->a--
,我可以理解sptr->a
是先完成然后再--
应用。
但在 的情况下--sptr->a
,--
应首先应用于sptr
。这可能会导致未定义的行为,但应该是这样。为什么这仍然与 一样有效sptr->a--
?
只有后缀递增/递减具有与 相同的优先级
->
。前缀递增/递减具有较低的优先级。因此在这种情况下
--
由于从左到右的关联性,最后应用。在案件中
--
->
由于优先级较高,所以最后应用。更新(因为问题中添加了“语言律师”标签):
C 标准的规范部分(请注意,下面的引用是 C23 草案 N3220,可能与最终版本不同)通过语言语法语法隐式地定义了运算符优先级和结合性。
第6.5.1-3条内容如下:
第 82 条注释如下:
“后缀运算符”(例如
->
和 postfix--
)见于第 6.5.3 节,“一元运算符”(例如 prefix--
)见于第 6.5.4 节。这确定了优先顺序(顺便说一下,第 6.5.3.1-1 和 6.5.4-1 节中的语法摘录也暗示了这一点)。为了确定结合性,后缀运算符(6.5.3.1-1)的语法如下:
这意味着,例如,表达式
sptr->a--
被解释为 (sptr->a
)--
。即
--
前面是后缀表达式sptr->a
。因此结合性是从左到右的。有关运算符优先级和结合性的完整表格(尽管基于 C11),请参见此处。
->
和postfix--
具有相同的优先级和从左到右的结合性,所以也是sptr->a--
如此(sptr->a)--
。->
和前缀的--
优先级不同,--
较低。--sptr->a
因此--(sptr->a)
。正如您在这里看到的,前缀增量/减量运算符的优先级为2 ,而后缀增量/减量运算符的优先级为1(如
->
运算符)。因此
sptr->a--
被解析为(sptr->a)--
,优先级相同,但是从左到右结合。并且
--sptr->a
被解析为--(sptr->a)
,因为前缀运算符的优先级低于->
。