わさっきhb

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

優先順位を,構文規則から考える

構造体のポインタで,間接参照演算子「*」を使ったメンバ変数の参照手順を以下に示しておこう.

(*record).name

()と「.」の優先順位は同じだが,この場合,評価順が左から右となり,(*record)が先に評価される.評価結果に対して「.」を評価するため,コンパイラは正しくnameメンバ変数を参照できる,という仕組みだ.
(ここが変だよC言語 下, pp.4-5)

『()と「.」の優先順位は同じだが』が間違いで,構文規則に基づいて考えると,()の優先順位は,「.」よりも高いです.
構文規則を,JIS X 3010 : 2003*1の6.5.1節と6.5.2節から抜き出してみました.

  • 「一次式」は,以下のいずれかである.
    • 識別子
    • 定数
    • 文字列リテラル
    • ( 式 ) ...ここ!!
  • 「後置式」は,以下のいずれかである.
    • 一次式
    • 後置式 [ 式 ]
    • 後置式 ( 実引数式並びopt )*2
    • 後置式 . 識別子 ...ここ!!
    • 後置式 -> 識別子
    • 後置式 ++
    • 後置式 --
    • ( 型名 ) { 初期化子並び }*3
    • ( 型名 ) { 初期化子並び, }

少なくとも,() と「.」のカテゴリが違うなあということが分かります.あとはこの種の構文規則の読み方を知っていれば*4,() の優先順位は,「.」よりも高いと結論付けられます.
ところで,上記の後置式の定義の中に,後置の増分・減分演算子が書かれています.「ということは前置と後置で,優先順位が違ってくるのか?」という疑問も生じるのですが,上巻の中に,これに関連しそうな気になる記述がありますので,後日,報告することにします.

「*record.name」と記述した場合,演算子の優先順位の規則から「*」より「.」が優先される.従って,まずrecord.nameを評価し,その結果に対して「*」が評価される.(略) ゆえに,「*record.name」はコンパイルエラーになる.
(前掲書, p.4)

それぞれの文は間違いでないのですが,違和感があります.
その理由を考えてみると,「演算子の優先順位は,式の評価方法how an expression is constructedを定めるものであり,式の評価順序を定めるものではない」のでした.
そういえばかつて日記に書いたぞ…これだ: ANDよりもORが優先することがある - わさっき

*1:PDF形式で閲覧できます: http://detail.chiebukuro.yahoo.co.jp/qa/question_detail.php?queId=9560176

*2:これは,関数の呼び出しを定めています.

*3:複合リテラル」と呼ばれます.

*4:「(*record).name」の構文木を書くというのでも,OKですね.