1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【C言語】ビット演算をしてみよう

Last updated at Posted at 2025-12-06

はじめに

この記事について

「C言語の基礎を学ぼう」をテーマに、自身の知識 + α をアドベントカレンダーにまとめます。
25日間でC言語をマスターしよう - Qiita Advent Calendar 2025 - Qiita

こんな方を対象としています

  • コンピュータがプログラムをどのように動かしているか知りたい/知らない方

  • プログラミングをしてみたい方

  • C言語初心者の方

キーワード

  • 2進数

  • 2の補数

  • ビット演算

  • マスク

説明

2進数

プログラム内のあらゆる値は2進数で管理されています。
この記事では2進数を扱ったプログラムについて紹介します。

0b を先頭につけることで2進数を表現することができます。
1001 を10進数として出力すると下記のようになります。

#include <stdio.h>
int main(void) {
    short num = 0b1001;
    printf("%d", num);
    return 0;
}
9

2進数は10進数と比較すると考えやすいです。

2進数と10進数の比較

10進数の10101は $10^4+10^2+10^0=10101$ と考えることができます。

2進数も同様に考えることができ、2進数の1001は $2^3+2^0=9$ となります。

10進数と2進数と16進数について、それぞれの対応は下記のようになります。

10進数 2進数 16進数
0 0000 0000 00
1 0000 0001 01
2 0000 0010 02
3 0000 0011 03
4 0000 0100 04
5 0000 0101 05
6 0000 0110 06
7 0000 0111 07
8 0000 1000 08
9 0000 1001 09
10 0000 1010 0A
11 0000 1011 0B
12 0000 1100 0C
13 0000 1101 0D
14 0000 1110 0E
15 0000 1111 0F
16 0001 0000 10
... ... ...
255 1111 1111 FF

2の補数

C言語の負の整数について、2進数では 2の補数表現 を使います。

ある数 $x$ について、 $x + y = 0$ となるような $y$ を、 $x$ の2の補数といいます。

例えば、2進数0101の2の補数について考えてみます。
ここは4ビットの世界だとしましょう。(ビット数が増えても同じ考え方ができます)
0101 + 1011 = 0000 となります。(5ビット目の1はあふれてしまう)
そのため、 0101 (10進数で5) の2の補数は 1011 となります。

確かめてみましょう。 short は2バイトなので 0000 0000 0000 0101 の2の補数は 1111 1111 1111 1011 ですね。

#include <stdio.h>
int main(void) {
    short num = 0b1111111111111011;
    printf("%d", num);
    return 0;
}
-5

2の補数を簡単に求める方法があります。

  1. ビット反転する
  2. 1を足す

上記の例もそのようになっていますね。

2バイトの場合、10進数と2進数の対応は下記のようになります。

10進数 2進数
32767 0111 1111 1111 1111
32766 0111 1111 1111 1110
... ...
0 0000 0000 0000 0000
-1 1111 1111 1111 1111
-2 1111 1111 1111 1110
-3 1111 1111 1111 1101
... ...
-32767 1000 0000 0000 0001
-32768 1000 0000 0000 0000

ビット演算

AND、OR、NOT、シフトについて紹介します。

AND

AND演算は下記のような演算です。日本語で「かつ」と考えるとわかりやすいです。

A B AND
0 0 0
0 1 0
1 0 0
1 1 1

C言語では & で表します。

#include <stdio.h>
int main(void) {
    short a = 0b0011, b = 0b0101;
    printf("%d", a & b); // a & b は 0001 になる = 10進数で1
    return 0;
}
1

OR

OR演算は下記のような演算です。日本語で「または」と考えるとわかりやすいです。

A B OR
0 0 0
0 1 1
1 0 1
1 1 1

C言語では | で表します。

#include <stdio.h>
int main(void) {
    short a = 0b0011, b = 0b0101;
    printf("%d", a | b); // a | b は 0111 になる = 10進数で7
    return 0;
}
7

NOT

NOT演算は下記のような演算です。否定、反転と考えるとよいですね。

A NOT
0 1
1 0

C言語では ~ で表します。

#include <stdio.h>
int main(void) {
    short a = 0b1111111111110000;
    printf("%d", ~a); // ~a は 1111 になる = 10進数で15
    return 0;
}
15

左シフト

左シフト演算は下記のような演算です。

A 左シフト
0000 0001 0000 0010

C言語では << で表します。

#include <stdio.h>
int main(void) {
    short a = 0b01;
    printf("%d", a << 2); // aを2回左シフトするから100 = 10進数で4
    return 0;
}
4

右シフト

右シフト演算は下記のような演算です。

A 論理右シフト 算術右シフト
0000 1000 0000 0100 0000 0100
1000 1000 0100 0100 1100 0100

シフトには論理シフト、算術シフトがあり、先頭ビットが1の場合は右シフトの挙動が異なります。環境によって論理右シフトか算術右シフトか異なることがあるようです。

C言語では >> で表します。

#include <stdio.h>
int main(void) {
    short a = 0b100;
    printf("%d", a >> 1); // aを1回右シフトするから010 = 10進数で2
    return 0;
}
2

マスク

特定のビットを0にすることを 0マスク 、1にすることを 1マスク といいます。
マスク操作は下記のように行います。

  • 0とANDすると、0でも1でも0になる = 0マスク

  • 1とORすると、0でも1でも1になる = 1マスク

#include <stdio.h>
int main(void) {
    short a = 0b01010011, b = 0b00001111;
    short c = a & b; // aの下位4ビットを残してほかの上位ビットを0マスク
    short d = a | b; // aの下位4ビットを1マスク
    printf("c: %d\n", c); // 0000 0011 = 10進数で3
    printf("d: %d\n", d); // 0101 1111 = 10進数で95
    return 0;
}
c: 3
d: 95

0マスクは マスクする以外のビットを取り出す という目的で使われることも多いです。

練習

1. 2倍にしよう

整数aを2倍にしよう。

100の2倍は200です!

ポイント

a * 2 をすれば良い・・・のですが、ビット演算を使ってみましょう。

$a = 2 ^ n + 2 ^ m + \dots $ であるとき、
$a \times 2
= (2 ^ n + 2 ^ m + \dots ) \times 2
= (2 ^ {n + 1} + 2 ^ {m + 1} + \dots ) $ であることを利用します。

解答例

#include <stdio.h>
int main(void) {
    short a = 100;
    printf("%dの2倍は%dです!", a, a << 1);
    return 0;
}
100の2倍は200です!

左シフト1回 = 2倍です。

2. 余りを求めよう

自然数aを8で割った余りを求めよう。

100を8で割った余りは4です!

ポイント

a % 8 をすれば良い・・・のですが、ビット演算を使ってみましょう。

$a = \dots + 2 ^ 4 + 2 ^ 3 + 2 ^ 2 + \dots $ であるとき、
$a
= \dots + 2 ^ 4 + 2 ^ 3 + 2 ^ 2 + \dots
= (\dots + 2 ^ 1 + 1) \times 2 ^ 3 + (2 ^ 2 + \dots)$ であることを利用します。

解答例

#include <stdio.h>
int main(void) {
    short a = 100;
    printf("%dを8で割った余りは%dです!", a, a & 0b111);
    return 0;
}
100を8で割った余りは4です!

$2^3$ で割ったあまりは下位3ビットと一致します。

3. -1倍しよう

ある数aを-1倍しよう。

100の-1倍は-100です!

ポイント

a * -1 をすれば良い・・・のですが、ビット演算を使ってみましょう。

2の補数表現の変換「ビット反転して1を足す」を実装しましょう。

解答例

#include <stdio.h>
int main(void) {
    short a = 100;
    printf("%dの-1倍は%dです!", a, ~a + 1);
    return 0;
}
100の-1倍は-100です!

おわりに

0と1を「あり」と「なし」と解釈すれば、1バイトで8つのフラグ管理をすることができます。少ないメモリ量で多くの状態を管理できて素晴らしいですね。

ビット演算はC言語ならでは感があって好きです。

参考文献

↓↓↓ はじめてプログラミングを学んだときに読んだ本です ↓↓↓
詳細(プログラミング入門 C言語)|プログラミング|情報|実教出版

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?