わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

増分・減分演算子は後置のほうが前置よりも優先順位が高いんじゃないか

当学科の学生でも,2〜3年生で,(Cの)プログラミングスキルをどのように上げていけばいいのか不安な学生におすすめしたい本です.読んですぐ分かるということはなくても,大規模なプログラミングをするときに得るものは多いと思います.
後半(「第5章 設計」以降)が書きたかったことなのだろうなと思い,飛ばし読みではありますが興味深く読めました.前半はC言語の概観ですが,説明不足,あるいは検証不足な箇所が目につきました.一例を挙げると,p.76下部のコード断片で

n = (p-a)/sizeof(int);
return (float)v / n;

として平均を求めていますが,2つのポインタpとaの差(間の要素数)を求めるのは,「n = p - a;」です.
今日取り上げたいのは,同書p.45の図2.12,演算子の優先順位に関する表です.
優先順位1にあるのが,「関数呼び出し() ドット. アロー-> 添字[] 前置++ 前置--」.そして優先順位2は「後置++ 後置-- 単項+ 単項- ! アドレス& 参照* sizeof」となっています.もう一つ.優先順位3は「キャスト (型名)」のみです.
ここで,前置と後置の演算子で優先順位を分ける理由が思いつきません.そもそも一つのオペランドに前置と後置の演算子が絡むことはありません.
無理に例を作ってみると,面白いコードができました.じゃなかった,結果になりました.

/* incdec.c */

#include <stdio.h>

int main(void)
{
  int d = 10;
  printf("%d\n", d);
  --d++;
  ++d--;
  (--d)++;
  --(d++);
  (++d)--;
  ++(d--);
  printf("%d\n", d);
  return 0;
}

何が面白いかというと,カッコつきの増分・減分演算子が,顔文字に見えるのです.左へ,右へ,左へ,右へ.
あほなこと言うてる場合やないゎ.GCCgcc (GCC) 3.4.4 (cygming special, gdc 0.12, using dmd 0.125))でコンパイルすると,以下の通り,失敗しました.

incdec.c: In function `main':
incdec.c:9: error: invalid lvalue in decrement
incdec.c:10: error: invalid lvalue in increment
incdec.c:11: error: invalid lvalue in increment
incdec.c:12: error: invalid lvalue in decrement
incdec.c:13: error: invalid lvalue in decrement
incdec.c:14: error: invalid lvalue in increment

9行目は「--d++;」ですが,エラーメッセージは,デクリメント演算子の対象が左辺値になっていないということです.ここから,まず「d++」を評価し,次に「--その結果」としているのが見て取れます.「その結果」は,「d」ではなく「dの値」です.これでは(--演算子オペランド(左辺値)にならないので,エラーということです.
10行目のエラーメッセージと合わせると,増分・減分で優先順位があるのではなく,前置・後置で優先順位があることが分かります.後置が先,前置が後で,前掲書の結果と反対という結論になります.
ここまで特定の処理系で見てきましたが,実は,これは規格を読めば容易に想像できるのでした.JIS X3010:2003では,6.5.2節(p.50)に,後置の増分・減分演算子を含む「後置式」の構文規則が,6.5.3節(p.57)で,前置の増分・減分演算子を含む「単項式」の構文規則が,それぞれ定義されています*1.「単項式: 後置式 | ++単項式 | --単項式」から,後置のほうが優先順位が高いことが確認できます.
結論としては,前掲書の優先順位1と2で,前置と後置が逆だということです.これは,単純ミスなのかもしれませんし,「前置が先に評価される」という思い込みから来たのかもしれません.
とはいえ,単項演算子の優先順位で目くじらを立てることはありません.後置の++と--を除けば,右結合なので式の構成が一意に定まりますし,後置の++と--については,あとで評価すると考えればいいのですから.

*1:いつも引いている『C言語によるプログラミング―スーパーリファレンス編』だと,12.2.2節,p.171です.