C言語基礎|整数の表示

同じ数でも表示のしかたで“見え方”が激変!10進・8進・16進・2進を自在に出力しよう。

整数は「中身は同じ」でも「表示」で理解が深まるよ

C言語で整数を扱っていると、普段は printf の %d(10進)だけで十分に見えます。
でも、ビット演算やマスク、シフトを学び始めると 10進表示だけだと状況が見えにくい ことが増えてきます。

たとえば同じ 255 でも…

  • 10進:255
  • 8進:377
  • 16進:FF
  • 2進:11111111

こうやって見せ方を変えるだけで、「ビットが全部1だ!」と一発で分かります。
この記事では 整数の表示(変換指定子と長さ修飾子) を整理して、最後に 2進表示(ビット表示) の作り方も丁寧に解説します。

変換指定子とは?printf が数を“どの進数で見せるか”を決める記号

printf は「表示フォーマット(書式文字列)」の中に、変換指定子(%〜)を置くことで、値の表示方法を決めます。

整数を表示する基本の変換指定子

表示したい内容変換指定子対象の代表的な型出力の例
符号付き整数を10進%dintprintf(%d, -12);-12
符号無し整数を10進%uunsignedprintf(%u, 12U);12
符号無し整数を8進%ounsignedprintf(%o, 12U);14
符号無し整数を16進(小文字)%xunsignedprintf(%x, 255U);ff
符号無し整数を16進(大文字)%Xunsignedprintf(%X, 255U);FF

表の説明

  • d は signed の 10進表示。
  • u は unsigned の 10進表示。
  • o は octal(8進)。
  • x / X は hex(16進)。x は a〜f、X は A〜F で出ます。
  • 2進表示の変換指定子は標準では用意されていないので、関数で自作します(後でやります)。

長さ修飾子:long や long long を正しく表示するための目印

int だけなら %d や %u でいいのですが、long や long long を表示する場合は、変換指定子の前に 長さ修飾子 を付けます。

長さ修飾子とよく使う組み合わせ

10進(符号付き)10進(符号無し)8進16進
int%d%u%o%x / %X
long%ld%lu%lo%lx / %lX
long long%lld%llu%llo%llx / %llX

表の説明

  • long は l を付ける(%ld, %lu …)。
  • long long は ll を付ける(%lld, %llu …)。
  • “型と指定子が合わない” と、表示が崩れたり未定義の動作に近い状況になったりするので、ここは丁寧に合わせるのがコツです。

桁数とゼロ埋め:%06o や %04X の意味

表示幅やゼロ埋めは、% の直後に数字を書きます。

幅指定とゼロ埋めの読み方

書き方意味例(値=26)出力例
%5u幅5で右寄せprintf(%5u, 26U);“ 26”
%06o幅6、足りない分は0で埋める(8進)printf(%06o, 26U);“000032”
%04X幅4、0埋め(16進、大文字)printf(%04X, 26U);“001A”

表の説明

  • 0埋めしたいときは、幅指定の先頭に 0 を付けます。
  • %06o は「8進で6桁、0で埋める」。
  • %04X は「16進(大文字)で4桁、0で埋める」。
    この形はビット列・レジスタ・ID表記の学習でめちゃくちゃ役立ちます。

2進表示は自作:下位nビットだけを表示する考え方

C標準の printf には 2進表示がないので、ビットを取り出して 0/1 を表示する関数を作ります。
ポイントはこの2つです。

  • 右シフト x >> i で「第iビットを最下位へ持ってくる」
  • 1U と AND を取って 0/1 を判定する((x >> i) & 1U)

第iビットを取り出す流れ

x の第 i ビットを知りたい
1) x >> i で i ビット右にずらす
2) (x >> i) & 1U で最下位ビットだけ取り出す
3) 1なら '1'、0なら '0' を表示

図の説明
右にずらすことで「知りたいビット」を一番右へ運び、最後に 1U でフタをして最下位だけを見るイメージです。

サンプルプログラム

学習にちょうどいいように 0〜31 だけを表示するプログラム例です。

プロジェクト名:chap7-22-1 ソースファイル名:chap7-22-1.c

// 0~31を10進/2進(下位8ビット)/8進/16進で表示
#include <stdio.h>
#include <limits.h>

// unsigned のビット数を数える(例:16や32など)
int count_bits(unsigned x)
{
    int bits = 0;
    while (x) {
        if (x & 1U) bits++;
        x >>= 1;
    }
    return bits;
}

// unsigned のビット数を返す
int uint_bits(void)
{
    return count_bits(~0U);
}

// unsigned 整数 x の下位 n ビットを表示する
void print_nbits(unsigned x, unsigned n)
{
    int total = uint_bits();
    int i = (n < (unsigned)total) ? (int)n - 1 : total - 1;

    for (; i >= 0; i--) {
        putchar(((x >> i) & 1U) ? '1' : '0');
    }
}

int main(void)
{
    printf("いろいろな進数で整数を見てみよう。\n");
    printf("10進  2進(下位8ビット)  8進     16進\n");

    for (unsigned i = 0U; i <= 31U; i++) {
        printf("%3u  ", i);          // 10進
        print_nbits(i, 8);           // 2進(下位8ビット)
        printf("      %04o   %02X\n", i, i); // 8進と16進(0埋め)
    }

    return 0;
}

このプログラムで確認できること

  • 同じ i を 10進・2進・8進・16進で並べて見られる。
  • 2進表示は関数 print_nbits で自作できる。
  • %04o や %02X のような 幅指定と0埋めの効果が見える。
  • 表示するビット数を 8 に固定したので、学習にちょうどいい長さで比較できる。

関数 print_nbits の動作を“箱とビット”で理解しよう

print_nbits(x, n) は「下位nビットを表示」と言っていますが、実装の中身はこうです。

print_nbits がやっていること(下位8ビットの例)

x = 13 のとき(下位8ビット)
00001101 を表示したい

i = 7 から 0 へ向かって繰り返す
x >> i で第iビットを最下位へ
& 1U で0/1を取り出す
0なら0、1なら1を出す

図の説明
上位(左)から順に出すために i を 7→0 と減らしています。
これで見た目が “ふつうの2進数表記” になります。

n が大きすぎるときの安全策(教材の重要ポイント)

元の説明にもあった通り、n が型のビット数を超えたらどうするかは注意点です。
この例では、n が unsigned のビット数を超えていたら 表示は型の全ビット数に丸めるようにしています。

print_nbits の n の扱い

指定した nunsigned のビット数が16の環境実際に表示するビット数
8下位8ビット8
16下位16ビット16
3216ビットしか存在しない16(丸める)

表の説明
「存在しないビットを表示しようとしても意味がない」ので、型のビット数を上限にしています。

ここで解説した命令(書式と何をするか)

この記事で登場した要素をまとめます。

printf と関連要素の書式

命令・要素書式何をする命令?
printfprintf(書式文字列, 値, …)値を文字列として表示する
変換指定子%d %u %o %x %X整数を10進/8進/16進で表示する指定
長さ修飾子l / lllong / long long を正しく表示するための目印
幅指定・0埋め%04o %02X など表示幅をそろえ、足りない分を0で埋める
>> 演算子a >> bビット列を右に b ビットずらす
& 演算子a & bビット単位のANDでマスクする
putcharputchar(文字)1文字だけ出力する(0/1表示に便利)