閉じる

【C言語】 printf書式指定子一覧と実例集|これだけ覚えればOK

C言語での画面出力はほぼすべてprintfから始まると言ってもよいほど重要です。

しかし、書式指定子(フォーマット指定)が分かりにくく、なんとなく使っている方も多いと思います。

この記事では「これだけ覚えれば実務で困らない」printfの書式指定子を一覧と実例付きで丁寧に解説します。

C言語のprintfとは

printfの基本構文と使い方

C言語のprintfは、標準ライブラリstdio.hに定義されている画面出力専用の関数です。

最も基本的な構文は次の形になります。

C言語
#include <stdio.h>

int main(void) {
    int score = 90;

    // 書式文字列と値を組み合わせて出力
    printf("合計 = %d 点\n", score);
    //       ^^^^^^^^ 書式文字列
    //                  ^^^^^ 引数(値)

    return 0;
}

このときの構文は次のように整理できます。

  • 最初の引数が書式文字列(format string)
  • 書式文字列の中に書式指定子(例: %d)を書く
  • 2番目以降の引数で、その%dなどに対応する値を渡す

書式指定子と引数の型が対応していることが非常に重要です。

たとえば%dならint%fならdoubleを渡す必要があります。

標準出力とフォーマット指定の役割

C言語には標準出力(standard output)という概念があります。

通常はコンソール(ターミナル)画面に接続されていて、printfはこの標準出力へ文字を送り出します。

フォーマット指定(書式指定子)には次のような役割があります。

  • 数値を10進数/16進数/8進数などで表示する
  • 桁数や小数点以下の桁数をそろえる
  • 左寄せ/右寄せ、ゼロ埋めなど見た目を整える
  • 文字列を一部だけ抜き出して表示する

「値」そのものは数値やポインタですが、printfはそれを人間が読みやすい文字列に変換する関数だと考えると理解しやすくなります。

printf書式指定子一覧

ここでは、まずよく使う書式指定子を一覧で整理します。

そのあと各項目を詳しく見ていきます。

代表的な書式指定子を一覧表にまとめます。

書式指定子意味対応する型(基本)
%d, %i符号付き10進整数int
%u符号なし10進整数unsigned int
%x, %X16進整数(小文字/大文字)unsigned int
%o8進整数unsigned int
%c1文字int(char昇格)
%s文字列char *
%f実数(小数点)double
%e, %E指数表記の実数double
%pポインタ(アドレス)void *など
%nここまでの文字数を格納int *など

このほかにも%g%aなどがありますが、まずは上の一覧を押さえれば一般的な開発で十分対応できます。

整数用書式指定子%dと%i

%d%i符号付き10進整数を表示します。

実務では%dを使うことがほとんどです。

C言語
#include <stdio.h>

int main(void) {
    int a = 10;
    int b = -20;

    printf("a = %d\n", a);  // 10進数で表示
    printf("b = %d\n", b);  // 符号付きで表示

    // %i も %d とほぼ同じように動く
    printf("a (%%i) = %i\n", a);
    printf("b (%%i) = %i\n", b);

    return 0;
}
実行結果
a = 10
b = -20
a (%i) = 10
b (%i) = -20

printfの中では%cst-code>%dと%iはほぼ同義と覚えておけば十分です。

符号なし整数用書式指定子%u

%u符号なし(unsigned)の10進整数を表示します。

C言語
#include <stdio.h>

int main(void) {
    unsigned int u = 4000000000U;
    int           s = -1;

    printf("unsigned = %u\n", u);

    // 故意に型を揃えない例(本来はNG)
    printf("signed(-1)を %%u で表示すると: %u\n", s);

    return 0;
}
実行結果
unsigned = 4000000000
signed(-1)を %u で表示すると: 4294967295

変数の型と書式指定子が一致していないと意味不明な値になるので、特に符号付きか符号なしかは常に意識する必要があります。

16進数・8進数表示の%xと%o

%x%oは、デバッグやビット操作の確認で頻出です。

C言語
#include <stdio.h>

int main(void) {
    unsigned int v = 255;

    printf("10進: %u\n", v);
    printf("16進(小文字): %x\n", v);
    printf("16進(大文字): %X\n", v);
    printf("8進: %o\n", v);

    return 0;
}
実行結果
10進: 255
16進(小文字): ff
16進(大文字): FF
8進: 377

ビット列を確認するときは16進数で見るほうが直感的な場合が多いため、%xは特に重要です。

文字・文字列表示の%cと%s

文字と文字列はよく似ていますが、型と意味がまったく違う点に注意が必要です。

C言語
#include <stdio.h>

int main(void) {
    char ch = 'A';             // 1文字
    char str[] = "Hello";      // 文字列(終端に '\0')

    printf("文字: %c\n", ch);
    printf("文字列: %s\n", str);

    // %c には int(実際はcharがintに昇格したもの)を渡す
    // %s には char * (文字列の先頭アドレス)を渡す
    return 0;
}
実行結果
文字: A
文字列: Hello

文字列リテラル”Hello”はchar *として扱われることも合わせて意識しておきましょう。

実数表示の%fと%e・%E

%f小数点付きの通常表記%e%E指数表記で実数を表示します。

いずれもdoubleが対象です。

C言語
#include <stdio.h>

int main(void) {
    double x = 12345.6789;

    printf("通常表記 %%f: %f\n", x);
    printf("指数表記 %%e: %e\n", x);
    printf("指数表記 %%E: %E\n", x);

    return 0;
}
実行結果
通常表記 %f: 12345.678900
指数表記 %e: 1.234568e+04
指数表記 %E: 1.234568E+04

既定では小数点以下6桁まで表示されます。

桁数をそろえたい場合は後述の%.2fのような精度指定を使います。

ポインタ表示の%p

%pポインタのアドレス値を表示します。

デバッグ時に非常によく使います。

C言語
#include <stdio.h>

int main(void) {
    int value = 100;
    int *p = &value;

    printf("value のアドレス: %p\n", (void *)&value);
    printf("p の値(同じアドレス): %p\n", (void *)p);

    return 0;
}
実行結果
value のアドレス: 0x7ffeefbff45c
p の値(同じアドレス): 0x7ffeefbff45c

%p ではvoid *にキャストして出力するのが標準的とされています。

printf書式指定子の詳細と応用

ここからは、書式指定子の「オプション部分」(フィールド幅、フラグ、精度など)について詳しく説明します。

書式指定子の一般形は次のようになります。

%[フラグ][フィールド幅][.精度][サイズ修飾子]変換指定子

フィールド幅と左寄せ・右寄せ

フィールド幅を指定すると、「その数だけの桁を使って表示する」ことができます。

足りない部分は空白で埋められます。

C言語
#include <stdio.h>

int main(void) {
    int n = 42;

    printf("右寄せ 幅5: '%5d'\n", n);
    printf("左寄せ 幅5: '%-5d'\n", n);

    return 0;
}
実行結果
右寄せ 幅5: '   42'
左寄せ 幅5: '42   '
  • %5d: 幅5、右寄せ(デフォルト)
  • %-5d: 幅5、左寄せ(-フラグ)

列をそろえたいときに非常に便利です。

ゼロ埋めと符号表示

0フラグをつけると、空白ではなく0で埋めることができます。

また+フラグでプラスの数にも+を表示できます。

C言語
#include <stdio.h>

int main(void) {
    int a = 42;
    int b = -42;

    printf("通常     : '%5d' '%5d'\n", a, b);
    printf("ゼロ埋め : '%05d' '%05d'\n", a, b);
    printf("符号表示 : '%+5d' '%+5d'\n", a, b);

    return 0;
}
実行結果
通常     : '   42' '  -42'
ゼロ埋め : '00042' '-0042'
符号表示 : '  +42' '  -42'

ゼロ埋めは符号の右側から埋まるため、負の値でも-0042のような表示になります。

精度指定(%.2fや%.3s)の使い方

精度指定は小数点以下の桁数や、文字列の最大文字数などを制御します。

C言語
#include <stdio.h>

int main(void) {
    double pi = 3.1415926535;

    printf("デフォルト  : %f\n", pi);
    printf("小数2桁     : %.2f\n", pi);
    printf("小数4桁     : %.4f\n", pi);
    printf("幅8, 小数2桁: %8.2f\n", pi);

    return 0;
}
実行結果
デフォルト  : 3.141593
小数2桁     : 3.14
小数4桁     : 3.1416
幅8, 小数2桁:     3.14
  • 実数: %.2fなら小数点以下2桁に丸めて表示
  • 文字列: %.3sなら最大3文字までを表示

文字列の切り出し表示(%.Ns)の実例

%.Nsを使うと先頭から最大N文字だけを表示できます。

ログ出力やテーブル出力で、長すぎる文字列を切りたいときに便利です。

C言語
#include <stdio.h>

int main(void) {
    char *s = "HelloWorld";

    printf("元の文字列        : '%s'\n", s);
    printf("先頭5文字だけ     : '%.5s'\n", s);
    printf("先頭8文字だけ     : '%.8s'\n", s);
    printf("幅10, 先頭5文字   : '%10.5s'\n", s);
    printf("左寄せ, 幅10,5文字: '%-10.5s'\n", s);

    return 0;
}
実行結果
元の文字列        : 'HelloWorld'
先頭5文字だけ     : 'Hello'
先頭8文字だけ     : 'HelloWor'
幅10, 先頭5文字   : '     Hello'
左寄せ, 幅10,5文字: 'Hello     '

幅と精度を組み合わせることで「切り出しつつ列をそろえる」ことができます。

フラグ(#, 0, +, 空白, -)の意味と使い分け

代表的なフラグを整理しておきます。

フラグ意味の概要
-左寄せ%-5d
+正数にも+を付ける%+d
(空白)正数のとき先頭に空白1つ(負数の-と幅を合わせる)% d
0ゼロ埋め%05d
#進数表記にプレフィックスや小数点を付ける%#x, %#o, %#f

具体例を見てみましょう。

C言語
#include <stdio.h>

int main(void) {
    int n = 255;

    printf("通常16進      : %x\n", n);
    printf("#付き16進     : %#x\n", n);
    printf("通常8進       : %o\n", n);
    printf("#付き8進      : %#o\n", n);

    double x = 10.0;
    printf("通常%%g        : %g\n", x);
    printf("#付き%%g       : %#g\n", x);

    return 0;
}
実行結果
通常16進      : ff
#付き16進     : 0xff
通常8進       : 377
#付き8進      : 0377
通常%g        : 10
#付き%g       : 10.0000

#フラグで「16進なら0x, 8進なら0を付ける」など、形式が明確になるため、デバッグ出力でよく使われます。

longやshortなどサイズ修飾子

整数型のサイズによってサイズ修飾子を付けます。

環境によって型サイズは異なりますが、書式と対応は次のようになります。

修飾子対応する型の例
なし%dint
h%hdshort
hh%hhdsigned char
l%ldlong
ll%lldlong long
z%zusize_t
t%tdptrdiff_t

実例として、long longの値を表示してみます。

C言語
#include <stdio.h>

int main(void) {
    long long big = 123456789012345LL;

    printf("long long: %lld\n", big);

    return 0;
}
実行結果
long long: 123456789012345

型に合った修飾子を使わないと未定義動作になるので、表と一緒に覚えておくと安全です。

printfでよくあるエラーと注意点

printfでよく起こる問題をまとめておきます。

1つ目は書式指定子と引数の型不一致です。

C言語
#include <stdio.h>

int main(void) {
    double x = 3.14;

    // 間違い: %d は int 用なのに double を渡している
    printf("値 = %d\n", x);  // 未定義動作、警告が出るはず

    return 0;
}

コンパイラの警告を必ず確認し、警告は0件を維持することが重要です。

2つ目は引数の個数が合わないパターンです。

C言語
#include <stdio.h>

int main(void) {
    int a = 10, b = 20;

    // NG: 書式文字列に2つの%dがあるのに、引数が1つしかない
    printf("a=%d, b=%d\n", a);  // 未定義動作

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

    return 0;
}

3つ目はポインタ型の誤用です。

C言語
#include <stdio.h>

int main(void) {
    char *s = "Hello";

    // NG: %d は整数用。ポインタを出したいなら %p を使う。
    printf("アドレス? %d\n", s);   // 未定義動作
    // OK:
    printf("アドレス: %p\n", (void *)s);

    return 0;
}

書式文字列がユーザー入力のまま使われると、%nなどを悪用した脆弱性につながる場合があります。

信頼できない入力をそのままprintfに渡さないようにしましょう。

よく使うprintf書式指定子の実例集

ここからは「そのままコピペして使える」ことを意識して、典型的な使い方をまとめます。

整数を桁揃えして表示する例

C言語
#include <stdio.h>

int main(void) {
    int values[] = {1, 20, 300, 4000};
    int i;

    printf("幅4で右寄せ:\n");
    for (i = 0; i < 4; i++) {
        // 幅4で右寄せ
        printf("%4d\n", values[i]);
    }

    printf("\n幅4で左寄せ:\n");
    for (i = 0; i < 4; i++) {
        // 幅4で左寄せ
        printf("%-4d\n", values[i]);
    }

    return 0;
}
実行結果
幅4で右寄せ:
   1
  20
 300
4000

幅4で左寄せ:
1   
20  
300 
4000

データの一覧を表示するときに、桁揃えができていると可読性が大きく向上します。

マイナス値とプラス値を揃えて表示する例

C言語
#include <stdio.h>

int main(void) {
    int vals[] = {-5, 10, -123, 45};
    int i;

    printf("符号あり右寄せ(幅5):\n");
    for (i = 0; i < 4; i++) {
        printf("%+5d\n", vals[i]);  // + フラグで正数にも+を付ける
    }

    printf("\n符号位置をそろえる(空白フラグ):\n");
    for (i = 0; i < 4; i++) {
        printf("% 5d\n", vals[i]);  // 空白フラグで正数は先頭に空白
    }

    return 0;
}
実行結果
符号あり右寄せ(幅5):
   -5
  +10
 -123
  +45

符号位置をそろえる(空白フラグ):
   -5
   10
  -123
   45

+フラグは「+/-をはっきり表示したいとき」、空白フラグは「正数はスペースで揃えたいとき」に使い分けます。

小数点以下の桁数をそろえる例

C言語
#include <stdio.h>

int main(void) {
    double vals[] = {3.1, 12.3456, 0.5, 123.0};
    int i;

    printf("デフォルト(%%f):\n");
    for (i = 0; i < 4; i++) {
        printf("%f\n", vals[i]);
    }

    printf("\n小数2桁(%%.2f):\n");
    for (i = 0; i < 4; i++) {
        printf("%.2f\n", vals[i]);
    }

    printf("\n幅8, 小数2桁(%%8.2f):\n");
    for (i = 0; i < 4; i++) {
        printf("%8.2f\n", vals[i]);
    }

    return 0;
}
実行結果
デフォルト(%f):
3.100000
12.345600
0.500000
123.000000

小数2桁(%.2f):
3.10
12.35
0.50
123.00

幅8, 小数2桁(%8.2f):
    3.10
   12.35
    0.50
  123.00

小数点以下の桁をそろえることで、値の比較や異常値の発見がしやすくなります

16進ダンプ風にバイト列を表示する例

メモリの内容を確認したいとき、16進数のダンプ表示が役立ちます。

C言語
#include <stdio.h>

int main(void) {
    unsigned char data[] = {0x00, 0x1F, 0xA0, 0xB3, 0xFF, 0x10, 0x20, 0x30};
    int i;
    int size = (int)(sizeof(data) / sizeof(data[0]));

    printf("バイト列(16進ダンプ風):\n");

    for (i = 0; i < size; i++) {
        // 2桁の16進数でゼロ埋め表示
        printf("%02X ", data[i]);

        // 8バイトごとに改行
        if ((i + 1) % 8 == 0) {
            printf("\n");
        }
    }

    // 末尾が8の倍数でなければ改行を入れる
    if (size % 8 != 0) {
        printf("\n");
    }

    return 0;
}
実行結果
バイト列(16進ダンプ風):
00 1F A0 B3 FF 10 20 30

%02X を使うと「幅2桁・ゼロ埋め・16進・大文字」で表示できます。

バイト列のデバッグでは定番のテクニックです。

文字列一覧を表形式で出力する例

C言語
#include <stdio.h>

int main(void) {
    const char *names[] = {"Alice", "Bob", "Catherine", "Dan"};
    const char *notes[] = {"OK", "NG: timeout", "OK", "pending"};
    int i;

    printf("+----+------------+--------------+\n");
    printf("| ID | 名前       | メモ         |\n");
    printf("+----+------------+--------------+\n");

    for (i = 0; i < 4; i++) {
        // IDを2桁右寄せ、名前を幅10左寄せ、メモを幅12左寄せ
        printf("| %2d | %-10.10s | %-12.12s |\n",
               i, names[i], notes[i]);
    }

    printf("+----+------------+--------------+\n");

    return 0;
}
実行結果
+----+------------+--------------+
| ID | 名前       | メモ         |
+----+------------+--------------+
|  0 | Alice      | OK           |
|  1 | Bob        | NG: timeout  |
|  2 | Catherine  | OK           |
|  3 | Dan        | pending      |
+----+------------+--------------+

ここでは幅指定と精度指定(%.10sなど)で、長すぎる名前やメモを切りつつ列をそろえる工夫をしています。

デバッグで値をまとめて表示するテクニック

デバッグ時には複数の値を1行にまとめて分かりやすく表示すると効率的です。

C言語
#include <stdio.h>

int main(void) {
    int  count = 10;
    int  err   = -2;
    double avg = 3.14159;
    const char *status = "running";

    printf("[DEBUG] count=%d, err=%d, avg=%.3f, status=%s\n",
           count, err, avg, status);

    // アドレスや16進数も一緒に表示
    printf("[DEBUG] &count=%p, err(hex)=%#x\n",
           (void *)&count, (unsigned int)err);

    return 0;
}
実行結果
[DEBUG] count=10, err=-2, avg=3.142, status=running
[DEBUG] &count=0x7ffee3cdd47c, err(hex)=0xfffffffe

「[DEBUG]」などのプレフィックスを付け、変数名と値をペアで表示すると、ログを後から見返したときに非常に分かりやすくなります。

16進数やアドレスも併せて出すことで、バグの原因特定に役立ちます。

まとめ

printfの書式指定子は一見複雑ですが、基本の%d/%u/%x/%s/%f/%pを押さえ、フィールド幅・精度・フラグの組み合わせ方に慣れてしまえば、実務でも強力な武器になります。

特に桁揃え・小数桁数の調整・16進ダンプ・テーブル表示・デバッグメッセージの5パターンを自分の定番スタイルとして持っておくと、毎日の開発がぐっと楽になります。

この記事のサンプルコードをベースに、自分のプロジェクト向けフォーマットを整えていきましょう。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!