C言語を習得する上で、演算子の正しい理解は避けて通れない極めて重要なステップです。

プログラムにおける「演算」とは、単なる四則演算だけでなく、値の比較、論理的な判断、さらにはメモリ上のビット操作まで多岐にわたります。

演算子を使いこなすことができれば、複雑な条件分岐や効率的なデータ処理を簡潔に記述できるようになります。

本記事では、C言語で利用される全主要演算子の種類から、初心者が混同しやすい優先順位、具体的な使い方まで、サンプルコードを交えて徹底的に解説します。

この記事を読み終える頃には、C言語の演算に関する基礎から応用までの知識が身についているはずです。

算術演算子:数値計算の基本

算術演算子は、数学的な計算を行うための演算子です。

加減乗除などの基本的な操作が含まれますが、C言語特有の挙動(特に整数の割り算など)には注意が必要です。

算術演算子の種類

C言語で使用される主な算術演算子は以下の通りです。

演算子名称意味
+加算a + baとbを足す
-減算a - baからbを引く
*乗算a * baとbを掛ける
/除算a / baをbで割る
%剰余a % baをbで割った余りを求める

除算と剰余演算の注意点

C言語の除算 / では、操作数が両方とも整数の場合、結果も整数になるという性質があります。

例えば、5 / 2 の結果は 2.5 ではなく、小数点以下が切り捨てられて 2 となります。

正確な小数値を求めたい場合は、少なくとも一方の数値を浮動小数点数(doublefloat)にする必要があります。

また、剰余演算子 % は整数に対してのみ使用可能です。

浮動小数点数に対して余りを求めたい場合は、標準ライブラリの fmod 関数を使用します。

算術演算子のサンプルプログラム

C言語
#include <stdio.h>

int main(void) {
    int a = 10;
    int b = 3;
    double x = 10.0;
    double y = 3.0;

    // 整数同士の計算
    printf("10 + 3 = %d\n", a + b);
    printf("10 - 3 = %d\n", a - b);
    printf("10 * 3 = %d\n", a * b);
    printf("10 / 3 = %d (整数のため切り捨て)\n", a / b);
    printf("10 %% 3 = %d (余り)\n", a % b);

    // 浮動小数点数を含む計算
    printf("10.0 / 3.0 = %f\n", x / y);

    return 0;
}
実行結果
10 + 3 = 13
10 - 3 = 7
10 * 3 = 30
10 / 3 = 3 (整数のため切り捨て)
10 % 3 = 1 (余り)
10.0 / 3.0 = 3.333333

代入演算子:変数への値の格納

代入演算子は、右辺の値を左辺の変数に格納するために使用されます。

もっとも基本的な = のほかに、演算と代入を同時に行う「複合代入演算子」が存在します。

複合代入演算子の一覧

複合代入演算子を使用すると、コードを簡潔に記述できます。

演算子展開した意味
=a = baにbを代入する
+=a += ba = a + b と同じ
-=a -= ba = a - b と同じ
*=a *= ba = a * b と同じ
/=a /= ba = a / b と同じ
%=a %= ba = a % b と同じ

代入演算子の性質

C言語における代入は、数学の「等しい」という意味ではなく、「右辺の評価結果を左辺のメモリ領域に書き込む」という動作を指します。

そのため、左辺には値を変更可能な変数(左辺値)が来る必要があります。

定数に対して代入を行うことはできません。

比較演算子(関係演算子・等価演算子):条件判定の要

比較演算子は、2つの値を比較して、その結果が「真」か「偽」かを判定します。

C言語では、真は 0 以外の値(通常は 1)、偽は 0 として扱われます。

比較演算子の種類

演算子名称意味(真となる条件)
==等号a == baとbが等しい
!=不等号a != baとbが等しくない
>より大きいa > baがbより大きい
<より小さいa < baがbより小さい
>=以上a >= baがb以上
<=以下a <= baがb以下

注意点:代入と等価の混同

初心者によくある間違いとして、比較のつもりで = を使ってしまうミスがあります。

if (a = 10) と記述すると、変数 a10 が代入され、その代入結果(10)が「真」と判定されてしまいます。

等しいかどうかを判定する場合は必ず == を使用してください。

論理演算子:複数の条件を組み合わせる

論理演算子は、複数の比較条件を組み合わせたり、条件を反転させたりするために使用されます。

主に if 文や while 文の条件式で活躍します。

論理演算子の種類

演算子名称意味
&&論理積 (AND)a && baとbが共に真なら真
\|\|論理和 (OR)a \|\| baまたはbのどちらかが真なら真
!論理否定 (NOT)!aaが真なら偽、偽なら真

短絡評価(ショートサーキット)

C言語の論理演算には「短絡評価」という重要な仕組みがあります。

  • && の場合:左辺が偽であれば、右辺の結果に関わらず全体が偽となるため、右辺は評価されません。
  • || の場合:左辺が真であれば、右辺の結果に関わらず全体が真となるため、右辺は評価されません。

これを利用して、例えば「ポインタが NULL でないことを確認してから、そのポインタの中身を参照する」といった安全なコードを書くことができます。

C言語
#include <stdio.h>

int main(void) {
    int score = 85;

    // scoreが80以上 かつ 100以下
    if (score >= 80 && score <= 100) {
        printf("優秀な成績です。\n");
    }

    // scoreが0未満 または 100より大きい
    if (score < 0 || score > 100) {
        printf("不正なスコアです。\n");
    }

    return 0;
}
実行結果
優秀な成績です。

インクリメント・デクリメント演算子

変数の値を1だけ増やしたり減らしたりする操作は非常に頻繁に行われるため、専用の演算子が用意されています。

演算子名称意味
++インクリメント++a / a++aを1増やす
--デクリメント--a / a--aを1減らす

前置と後置の違い

演算子を変数の前に置くか(前置)、後に置くか(後置)で、式の評価タイミングが異なります。

  • 前置 (++a): 変数の値を増やした後に、その値を式の結果として返します。
  • 後置 (a++): 現在の変数の値を式の結果として返した後に、変数の値を増やします。
C言語
#include <stdio.h>

int main(void) {
    int a = 5;
    int b = 5;

    printf("前置: %d\n", ++a); // 6が表示される
    printf("後置: %d\n", b++); // 5が表示された後、bは6になる
    printf("後置の後のb: %d\n", b);

    return 0;
}
実行結果
前置: 6
後置: 5
後置の後のb: 6

ビット演算子:低レイヤの操作

C言語はハードウェアに近い制御が可能な言語であり、メモリ上のビット(0と1)を直接操作する演算子が豊富です。

組み込み開発やフラグ管理、データの圧縮などで多用されます。

ビット演算子の種類

演算子名称意味
&ビット論理積 (AND)a & b各ビットごとにANDをとる
\|ビット論理和 (OR)a \| b各ビットごとにORをとる
^ビット排他的論理和 (XOR)a ^ b各ビットごとにXORをとる
~ビット反転 (NOT)~a全ビットを反転させる
<<左シフトa << naをnビット左にずらす
>>右シフトa >> naをnビット右にずらす

ビット演算の活用例

ビット演算を使用すると、特定のビットを「立てる(1にする)」、「落とす(0にする)」、「反転させる」といった操作が高速に行えます。

例えば、a << 1 は数値を2倍にすることに相当し、a >> 1 は数値を2で割る(小数点以下切り捨て)ことに相当します。

C言語
#include <stdio.h>

int main(void) {
    unsigned char a = 0x05; // 2進数で 0000 0101
    unsigned char b = 0x03; // 2進数で 0000 0011

    printf("AND: %02X\n", a & b); // 0000 0001 -> 0x01
    printf("OR:  %02X\n", a | b); // 0000 0111 -> 0x07
    printf("XOR: %02X\n", a ^ b); // 0000 0110 -> 0x06
    printf("左シフト: %02X\n", a << 1); // 0000 1010 -> 0x0A

    return 0;
}
実行結果
AND: 01
OR:  07
XOR: 06
左シフト: 0A

三項演算子(条件演算子)

三項演算子は、C言語の中で唯一3つの操作数を取る演算子です。

if-else 文を一行で簡潔に記述したい場合に便利です。

書式: 条件式 ? 真の場合の値 : 偽の場合の値

C言語
#include <stdio.h>

int main(void) {
    int x = 10;
    int y = 20;
    int max;

    // xとyの大きい方を代入
    max = (x > y) ? x : y;

    printf("大きい方は %d です。\n", max);

    return 0;
}
実行結果
大きい方は 20 です。

使いすぎるとコードの可読性を下げる可能性があるため、単純な代入や関数の引数などで限定的に使用するのが推奨されます。

sizeof演算子とキャスト演算子

これらは数値計算とは少し毛色が異なりますが、プログラムの動作を制御するために欠かせない演算子です。

sizeof演算子

sizeof は、型や変数が占有するメモリのサイズ(バイト数)を求める演算子です。

配列の要素数を求めたり、動的メモリ確保(malloc など)を行う際に必須となります。

キャスト演算子(型変換)

一時的にデータの型を変換するために使用します。

(型名)式 のように記述します。

C言語
#include <stdio.h>

int main(void) {
    int a = 5, b = 2;
    double result;

    // キャストなし:整数除算になり 2.0 になる
    result = a / b;
    printf("キャストなし: %f\n", result);

    // キャストあり:aをdoubleとして扱うため 2.5 になる
    result = (double)a / b;
    printf("キャストあり: %f\n", result);

    printf("int型のサイズ: %zu バイト\n", sizeof(int));

    return 0;
}
実行結果
キャストなし: 2.000000
キャストあり: 2.500000
int型のサイズ: 4 バイト

演算子の優先順位と結合規則

一つの式の中に複数の演算子が含まれる場合、どの演算から実行されるかは「優先順位」によって決まります。

また、同じ優先順位の演算子が並んだ場合にどちらから計算するかを「結合規則」と呼びます。

主要な演算子の優先順位表(高い順)

優先順位演算子結合規則
1(), [], ->, .左から右
2++, -- (後置)左から右
3++, -- (前置), !, ~, (型), * (ポインタ), & (アドレス), sizeof右から左
4*, /, %左から右
5+, -左から右
6<<, >>左から右
7<, <=, >, >=左から右
8==, !=左から右
9& (ビット論理積)左から右
10^左から右
11\|左から右
12&&左から右
13\|\|左から右
14?: (三項演算子)右から左
15=, +=, -= など右から左
16, (カンマ)左から右

迷ったときは括弧を使う

優先順位をすべて暗記するのは大変です。

意図しない計算順序を防ぐため、また他の開発者がコードを読みやすくするために、少しでも複雑な式になる場合は () を使って明示的に順序を指定するのがプロのエンジニアの作法です。

例えば、a + b * ca + (b * c) と同じですが、括弧を付けることで「先に掛け算をする」という意図が明確になります。

まとめ

C言語の演算子は、プログラムの挙動を制御するための最小単位であり、非常に多機能です。

  • 算術演算子は整数除算の切り捨てに注意する。
  • 代入演算子は複合代入を活用して簡潔に書く。
  • 比較・論理演算子は条件分岐の論理を構築する。
  • ビット演算子はハードウェア制御や最適化に利用する。
  • 優先順位で迷ったら、安全のために括弧 () を多用する。

これらの演算子を組み合わせて使いこなすことで、C言語の持つポテンシャルを最大限に引き出すことができます。

まずは基本的な算術演算と比較演算から慣れていき、徐々にビット演算や三項演算子などを取り入れて、より洗練されたコードを目指しましょう。