演算子とオペランドの組み合わせのことを式と呼びます。
「sum = 30 + 40 + 50 + 60 + 70」は、代入演算子と+演算子、変数と定数というオペランドから成り立っていますので式です。ここから一部を抜き出した「30 + 40」や、変数のみを抜き出した「sum」も式です。
式のうしろに“;”(セミコロン)を加えると式文になります。Cにおけるセミコロンは、ちょうど日本語における“。”(句点)のようなもので、式の後にこれがあることで1つの文として成り立ちます。
文は、式文以外の文も含めて、すべて上から順番に実行されます。つまり日本語のように上から書いてある順に読んでいけば意味が通るように、順序通り実行されます。しかしながら式についてはそうではありません。
例えば「a + b * c / d」という式を考えてみましょう。もちろん、優先順位が+演算子より*演算子および/演算子の方が高いため、「b * c / d」という式が先に演算されます。では*演算子と/演算子はどうでしょうか。優先順位は同じです。この場合は結合規則により、左側にある演算子(この場合は*演算子)が先に計算されます。
結合規則とは、このように同じ優先順位の演算子が1つの式に含まれていた場合、どちらの演算子を優先するかという規則です。ほとんどの演算子は*演算子や/演算子のように左の演算子が優先されます。ただし、「単項演算子」「キャスト演算子」「条件演算子」「代入演算子」は右にある演算子が優先されます。
これらの優先順位を変えるには、優先したい演算を“()”(丸かっこ)で囲います。「a + b * c / d」でa + bを先に計算したければ「(a + b) * c / d」となります。
なお、1つの式の中では、1つの変数の値を変更できるのは1回に限ります。
これはつまり、「a = a + 1」という書き方は問題ありませんが、「a = ++a + 1」のような書き方はできないということです。この1つの式の中で、「++a」で変数aの値が変更された後、さらに代入演算子を使って変数aの値を変更しようとしているからです。
「1つの式の中では」1つの変数に値を変更できるのは1回に限ると書きましたが、厳密には「直前の副作用完了点から次の副作用完了点までの間に」と定義されていますので、必ずしも「1つの式の中」とは限りません。式文の終わりはもっとも分かりやすい副作用完了点ですが、例えば論理AND演算子(&&)、論理OR演算子(||)、条件演算子(?:)、コンマ演算子(,)には副作用完了点が存在しますので、1つの式文の中でも2回以上変更可能です。これらの演算子については、今後の記事で説明したいと思います。
ただし、同じ変数の値を1つの式の中で何度も変更することは、書きやすさ、読みやすさの点からあまりおすすめできません。ひとつの式でひとつのことを行うことを心がければ、きっと分かりやすいプログラムになるでしょう。
式が表す値のことを式の値と言い、式の値を求めることを評価と言います。
式は、プログラムの実行時に評価され、式の値を持ちます。四則演算や論理演算を行う演算子では、単純に計算結果が式の値になりますので、これまで「計算結果」と言っていたものは式の値ということになります。式「30」の値は30で、式「30 + 40 + 50 + 60 + 70」の値は250です。「sum = 30 + 40 + 50 + 60 + 70」は、「30 + 40 + 50 + 60 + 70」という式の評価結果である250が、変数sumに代入されると解釈することができます。
ところで、「sum = 30 + 40 + 50 + 60 + 70」も、もちろん式です。式であるということは、実行時に評価され、式の値が求められます。代入演算子では、左オペランドに代入された値が式の値になります。つまり、式「sum = 30 + 40 + 50 + 60 + 70」の値は250です。
たいていの演算子は計算結果が式の値になりますので、そのルールは単純です。ところが、後置演算子だけは異色です。後置演算子とは、左オペランドだけを持つ++(インクリメント)と--(デクリメント)の演算子です。
これらは、計算を行う前のオペランドの値が式の値になります。次のプログラムで、前置演算子との動きを比較してみましょう。
#include <stdio.h> #include <stdlib.h> int main(void) { int x = 0; int y = 0; printf("%d, %d\n", ++x, y++); printf("%d, %d\n", x, y); return EXIT_SUCCESS; }
1, 0 1, 1
変数xは前置演算子を、変数yは後置演算子を使ってインクリメントしています。実行すると最初に「1, 0」、そして次の行に「1, 1」と表示されるはずです。5行目と6行目から分かるように、インクリメントする前は両方とも0です。実行結果から分かるように、インクリメント後には両方とも1になっています。
ここで、7行目の出力に注目してください。前置演算子を使ったxはインクリメント後の値である1が表示されますが、後置演算子を使ったyはインクリメント前の値である0が表示されます。
どちらもよく使われる演算子ですので、この挙動は覚えておくといいと思います。こんがらかってしまう場合は、「++x:インクリメント(++)されてから式の値が決まる」「y++:式の値が決まってからインクリメント(++)される」と覚えてみましょう。
前回と今回は盛りだくさんの内容で、お腹いっぱいになったと思います。Cプログラミングには、こんなに細かなことまで必要なのかと驚かれた方もいるかもしれません。Cは、さまざまな環境に対応しつつ、プログラマがやりたいことを妨げないような言語仕様とするために、このような作りになっているのです。
これだけのものを覚えるのは確かに大変ですが、どのような動きになっているかを知ることで、思い通りにプログラミングできるようになります。Cプログラミングにおいて、整数と整数の演算は、もっともよく使われる処理でしょう。それをきちんと知ることによって、バグが少なく、セキュリティにも優れたプログラムを書くことができるのです。
Copyright © ITmedia, Inc. All Rights Reserved.