View on GitHub

SSR C11 Textbook

四則演算

Back to the ToC


C言語では,電卓と同じように,四則演算を行うことができます. しかし,数学ほど自由に記述はできません. 言語仕様で決められた,限られた表現の中で,欲しい計算結果を得る必要があります. また,第2章で学んだ「型」というものも,計算結果に影響を与えます. 本章では,プログラムにおいてどのような四則演算ができ,どのような制約があるかを学んでいきます.

オペレータとオペランド

算数や数学で利用する,足し算のプラス (+) や引き算のマイナス(-)のことを,演算子またはオペレータ (operator)と呼びます. また,「足される数」や「足す数」のような,演算の対象となるものを,被演算子またはオペランド (operand) と呼びます. 特に,1+2のような複数のオペランドがある計算の場合,オペレータ左側の1を第一オペランド,オペレータ右側の2を第二オペランドと呼ぶことがあります. これらの単語は,計算機科学の分野でよく使われますので,覚えておいて損はないでしょう.

それでは,実際のC言語の四則演算を見ていきましょう. 下表に,C言語で使うことのできる四則演算子をまとめています. 剰余演算子のみ,被演算子が共に整数型のときしか使えませんので注意しましょう. それから,0で割り算を実行するのは厳禁です.

名前 記号 用法 演算の意味
加算演算子 プラス (+) a + b abの和
減算演算子 マイナス (-) a - b abの差
乗算演算子 アスタリスク (*) a * b abの積
除算演算子 スラッシュ (/) a / b abの商(bは非零)
剰余演算子 パーセント (%) a % b abで割った余り(bは非零)

使い方は極めてシンプルです. 次の例を見てみましょう.

#include <stdio.h>

int main(void) {
    int a = 10, b = 3;
    int c = a + b;
    printf("a + b = %d\n", c);
    c = a - b;
    printf("a - b = %d\n", c);
    c = a * b;
    printf("a * b = %d\n", c);
    c = a / b;
    printf("a / b = %d\n", c);
    c = a % b;
    printf("a %% b = %d\n", c);
    return 0;
}

このプログラムの出力は,次のようになります.

a + b = 13
a - b = 7
a * b = 30
a / b = 3
a % b = 1

割り算の結果の違和感は,次の節で解説します.

なお,四則演算を利用は,必ずしも代入を必要としません. 例えば,a + bという足し算の結果を出力したいときは,わざわざ新たな変数cを使わずに,

printf("a + b = \%d\n", a + b);

のように書くこともできます. 演算子は,使用された時点で演算を実行します.

演算の順序

C言語においても,四則演算には決まった順序が存在します. 四則演算に限れば,優先順位は数学とおよそ同じで,次のとおりです.

  1. 小括弧で囲われた中の演算
  2. 乗除算,剰余演算
  3. 加減算

例えば,

a = (2 + 3) * 5;

という計算をしたら,aには25という値が入ることになるわけです. 複雑な計算をさせるときは,小括弧を付け忘れないように気をつけましょう.

余談ですが,もっと細かい計算順序を決めたいときには,注意が必要です. もし

a = (1 + 2) + (3 + 4);

のような処理をしようとしたとき,全体の計算結果は一意ですが,左の1 + 2と右の3 + 4の優先度は同列であり,どちらが先に実行されるのかはわかりません.

もしこれらに明確な順序付けを行いたい場合は,別の変数を予め用意する必要があります. 今回の例だと,変数`b, c}を用意して

b = 1 + 2;
c = 3 + 4;
a = b + c;

のようにすれば,確実に`1+2}の方が先に計算されるようになります.

複合代入

プログラムを書いていくうちに,aの値をbだけ増やしたい,あるいはaの値をb倍にしたい,といった場面が生じてくることでしょう. このとき,素直に

a = a + b;  // a + bの結果をaへ代入
a = a * b;  // a * bの結果をaへ代入

と書いても何ら問題ありません. 一方でC言語では,複合代入 (compound assignment) と呼ばれる操作を行うことができます. 複合代入を用いることで,同じ処理を次のように略記することができます.

a += b;  // a + bの結果をaへ代入
a *= b;  // a * bの結果をaへ代入

四則演算に関する複合代入の演算子の一覧を,下表に示します.

名前 記号 用法 等価な演算
加算代入演算子 += a += b; a = a + b;
減算代入演算子 -= a -= b; a = a - b;
乗算代入演算子 *= a *= b; a = a * b;
除算代入演算子 /= a /= b; a = a / b;
剰余代入演算子 %= a %= b; a = a % b;

インクリメント・デクリメント

複合代入において,特に整数型の変数の値を+= 1-= 1をしたいとき,より簡単に記述することができます. 整数型の変数の値を1だけ増やす操作をインクリメント (increment), 逆に1だけ減らす操作をデクリメント (decrement) と呼びます.

以下の3つのコードは全て同じ動作をします.

int a = 0;
a = a + 1;
int a = 0;
a += 1;
int a = 0;
++a;

このプラス(+) を2つ並べた++を,インクリメント演算子と呼びます.

同様に,デクリメントはデクリメント演算子--を用いて,

int a = 0;
--a;  // <=> a -= 1; <=> a = a - 1;

と書くことができます. シンプルで,かつわかりやすい記法です.

文献やソースコードによっては,a++;a--;のように,演算子を後置することがあります. どちらの記法も,文法上問題はなく,どちらも正しく動くことでしょう. しかし,前置と後置では,評価順序 (evaluation order) が異なります. 評価順序とは,例えば足し算より掛け算を先に行うようなものです.

※似たような言葉で,演算子の結合順位というものがありますが,これはまた別物ですので注意してください.

この評価順序がなんと前置と後置で変わってしまうので,使用の際には注意が必要になります. 次のプログラムを実行してみましょう.

#include <stdio.h>

int main(void) {
    // 前置の場合
    int x = 0;
    int a = 3 + ++x;
    int b = ++x + 3;

    // 後置の場合
    x = 0;
    int c = 3 + x++;
    int d = x++ + 3;

    printf("a = %d, b = %d, c = %d, d = %d\n", a, b, c, d);

    return 0;
}

abの値とcdの値は同じになっているでしょうか?

評価順序について本講習会では詳細は扱いませんが,「確実に動かしたいときはセミコロンを挟もう!」というのが,著者から初心者へのメッセージです. 要はa = 3 + x++;のような,高度な知識がないと結果がわからない書き方をするのではなく,x++;してからa = 3 + x;とすれば,誰でも分かるように1増やされたx3に足されるわけです.

興味のある方は以下の文献をご参照ください. プログラミングを極める意思があるのであれば,副作用 (side effect) や副作用完了点 (sequence point) といったキーワードを覚えておくと良いでしょう.

GoogleのC++のスタイルガイドは,整数型でのインクリメント・デクリメントはどちらを用いても良いとしています. 著者としては前置記法(++a)の書き方に慣れておくことを薦めますが,各自の判断で使い分けてください.

C言語でインクリメントやデクリメントを使う上では,

  1. 自分,あるいはチームの中で前置・後置どちらの記法を使うかを決めておくこと
  2. 演算の優先順位が異なるという事実を認識しながら書くこと

の二点が重要です.


Back to the ToC

Previous: 変数と型 / Next: 出力関数printf


(c) 2017-2021 Yuki Onishi