Digamos que eu tenha uma estrutura
struct s
{
int a;
}
e uma função principal como esta
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;
}
Saída :
9
9
De acordo com a precedência do operador, ->
eles --
têm a mesma precedência e associatividade esquerda->direita.
No caso de sptr->a--
, posso entender sptr->a
que foi feito primeiro e depois --
aplicado.
Mas no caso de --sptr->a
, --
deve ser aplicado a sptr
primeiro. Isso pode levar a um comportamento indefinido, mas deve ser o caso. Por que isso ainda funciona da mesma forma que sptr->a--
?
É apenas o incremento/decremento pós-fixado que tem a mesma precedência que
->
. O incremento/decremento prefixado tem precedência menor.Assim no caso
--
é aplicado por último devido à associatividade da esquerda para a direita.No caso
--
é aplicado por último por->
ter maior precedência.Atualização (já que a tag "language-lawyer" foi adicionada à pergunta):
A parte normativa do Padrão C (observe que as referências abaixo são ao rascunho C23 N3220, que pode diferir da versão finalizada) define a precedência e a associatividade do operador de forma bastante implícita pela gramática da sintaxe da linguagem.
A cláusula 6.5.1-3 diz:
E a nota 82 diz:
"Operadores pós-fixados" (como
->
e pós-fixados--
) são encontrados na seção 6.5.3 e "Operadores unários" (como prefixo--
) são encontrados na seção 6.5.4. Isso estabelece a ordem de precedência (que, a propósito, também é implícita pelos trechos gramaticais nas cláusulas 6.5.3.1-1 e 6.5.4-1).Para determinar a associatividade, a sintaxe para operadores Postfix (6.5.3.1-1) é a seguinte:
O que implica que, por exemplo, a expressão
sptr->a--
é interpretada como (sptr->a
)--
.Ou seja,
--
é precedida pela expressão pós-fixasptr->a
. Assim, a associatividade é da esquerda para a direita.Para uma tabela completa de precedência e associatividade de operadores (embora baseada em C11), veja aqui .
->
e pós-fixo--
têm a mesma precedência e associatividade da esquerda para a direita, assimsptr->a--
como(sptr->a)--
.->
e prefixo--
não tem a mesma precedência,--
é menor. Assim--sptr->a
é--(sptr->a)
.Como você pode ver aqui, a precedência dos operadores de incremento/decremento prefixados é 2 , enquanto a precedência dos operadores de incremento/decremento pós-fixados é 1 (como o
->
operador ).Portanto,
sptr->a--
é analisado como(sptr->a)--
, mesma precedência, mas associatividade da esquerda para a direita.E
--sptr->a
é analisado como--(sptr->a)
, porque o operador de prefixo tem precedência menor que->
.