C言語の基本|printfで表示を整える

表示の幅や桁数をそろえると、結果はぐっと読みやすくなる。printfのフィールド幅・フラグ・精度を使って、伝わる出力を作ろう。

printfは、文字や数値を画面に出すだけの関数ではありません。表示する幅や位置、桁数などを細かく指定する機能も備えています。

たとえば、次のような表示ができます。

  • 数値を右側または左側へそろえる
  • 異なる桁数の数値を同じ幅で並べる
  • 空いている部分を0で埋める
  • 正の数にもプラス記号を付ける
  • 8進数や16進数の表記を分かりやすくする
  • 小数点以下の桁数をそろえる
  • 文字列の表示範囲を制限する

整形していない数値を縦に並べると、桁数が違うため比較しにくくなることがあります。

5
120
38
2400

フィールド幅を指定して右側へそろえると、次のように見やすくなります。

   5
 120
  38
2400

このような表示は、学習中の動作確認、簡単な表、ログ、一覧などで役立ちます。

ここでは、printfの書式指定を構成するフィールド幅、フラグ、精度について、実行結果を見ながら確認していきましょう。

printfの書式指定の全体像

printfの書式指定には、これまで使用してきた%dや%fの間に、追加の情報を記述できます。

基本的な並びは次のとおりです。

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

それぞれの役割を整理すると、次のようになります。

部分役割
%書式指定の開始%
フラグ左詰めや0埋めなどを指定-、+、#、0
フィールド幅表示に確保する最小幅5、8、10
.精度小数や文字列の表示範囲を指定.2、.4
修飾子データ型の長さなどを指定今回は詳しく扱わない
変換指定子値の表示形式を決めるd、f、s、x

たとえば、次の指定があります。

%5d

これは、int型の整数を最低5文字分の幅で右詰め表示する指定です。

%-5d

-フラグが加わっているため、最低5文字分の幅で左詰め表示します。

%.2f

double型の値を、小数点以下2桁で表示します。

%10.2f

全体を最低10文字分の幅にし、小数点以下を2桁にします。

書式指定は記号が多く見えますが、左から順番に分ければ意味を読み取りやすくなります。

フィールド幅とは

フィールド幅は、値を表示するために確保する最小の横幅です。

整数を最低5文字分の幅で表示する場合は、次のように書きます。

printf("[%5d]\n", 10);

実行結果は次のとおりです。

[   10]

値10は2桁です。フィールド幅として5文字分が指定されているため、不足する3文字分が空白になります。

角括弧はフィールド幅に含まれていません。空白の位置を分かりやすく確認するために表示しています。

指定がなければ右詰めになる

フィールド幅だけを指定した場合、値は右側へ寄せて表示されます。

printf("[%6d]\n", 58);

[    58]

58は2桁なので、左側に4文字分の空白が入ります。

内容文字数
左側の空白4
数値582
合計6

数値を縦に並べる場合は、右詰めにすると桁の位置がそろいます。

printf("[%6d]\n", 5);
printf("[%6d]\n", 120);
printf("[%6d]\n", 2400);

[     5]
[   120]
[  2400]

フィールド幅は最小幅

フィールド幅は、表示できる最大文字数ではありません。最低限確保する幅です。

次の例では、幅3を指定しています。

printf("[%3d]\n", 10000);

値10000は5桁なので、指定した幅3には収まりません。

実行結果は次のようになります。

[10000]

値が途中で切り捨てられることはありません。必要な幅まで自動的に広がります。

指定した幅より短い値 → 不足分を空白で埋める
指定した幅より長い値 → 値をすべて表示する

図1:フィールド幅5で整数を右詰めする仕組み

この図から分かること

%5dは、整数を最低5文字分の幅で表示する指定です。

値10は2桁なので、左側に3文字分の空白が入ります。フラグを指定していないため、数値は右詰めになります。

浮動小数点数のフィールド幅

浮動小数点数にもフィールド幅を指定できます。

printf("[%12f]\n", 123.456);

%fで精度を省略すると、小数点以下が6桁表示されます。

123.456000

この表示は、次の10文字で構成されています。

  • 整数部分の123で3文字
  • 小数点で1文字
  • 小数部分の456000で6文字

合計10文字です。フィールド幅は12なので、左側に2文字分の空白が入ります。

[  123.456000]

フィールド幅には、数値の数字だけでなく、次のものも含まれます。

  • 符号
  • 小数点
  • 小数部分
  • 8進数や16進数の接頭辞

フラグで表示方法を変える

フラグは、値をどのように整えて表示するかを追加で指定する記号です。

今回扱う主なフラグは次の4つです。

フラグ役割書式指定例表示例
-左詰め%-5d[10 ]
+正の値にも符号を付ける%+d[+10]
#進数の表記を明示する%#x[0xa]
0空いている部分を0で埋める%05d[00010]

-フラグで左詰めにする

通常のフィールド幅では、値は右詰めになります。

printf("[%5d]\n", 10);

[   10]

-フラグを付けると、左詰めになります。

printf("[%-5d]\n", 10);

実行結果は次のとおりです。

[10   ]

違いを並べると分かりやすくなります。

書式指定詰める方向表示結果
%5d右詰め[ 10]
%-5d左詰め[10 ]

文字列の項目名を左へそろえたいときにも利用できます。

printf("[%-10s]\n", "Sensor");

[Sensor    ]

+フラグで符号を表示する

通常、正の整数にはプラス記号が表示されません。

printf("[%d]\n", 10);

[10]

+フラグを付けると、正の値にもプラス記号を付けられます。

printf("[%+d]\n", 10);

[+10]

負の数には、通常どおりマイナス記号が表示されます。

printf("[%+d]\n", -10);

[-10]

増減量や温度差など、正負を明確に示したい表示に便利です。

printf("前日からの変化: %+d\n", 5);

前日からの変化: +5

#フラグで進数の表記を明示する

#フラグは、8進数や16進数を表示するときに、その表記形式を分かりやすくします。

16進数の場合は、0xまたは0Xが付きます。

unsigned int code = 42;

printf("%#x\n", code);
printf("%#X\n", code);

0x2a
0X2A

8進数の場合は、先頭に0が付きます。

unsigned int code = 42;

printf("%#o\n", code);

052

#フラグを使わない場合と比べると、進数を判断しやすくなります。

書式指定表示結果意味
%o528進数
%#o0528進数の表記を明示
%x2a小文字の16進数
%#x0x2a小文字の16進数であることを明示
%X2A大文字の16進数
%#X0X2A大文字の16進数であることを明示

%o、%x、%Xには、unsigned int型の値を渡します。

0フラグで空きを0にする

0フラグをフィールド幅と組み合わせると、通常なら空白になる部分が0で埋められます。

printf("[%05d]\n", 10);

実行結果は次のとおりです。

[00010]

書式指定を分けると、次のようになります。

部分意味
%書式指定の開始
0空きを0で埋める
5最低5文字分の幅
dint型の整数を10進数で表示

連番や管理番号など、桁数をそろえたい場合に利用できます。

printf("番号: %05d\n", 27);

番号: 00027

左詰めと0埋めの違い

%-5dと%05dは、どちらも幅5を指定していますが、表示方法が異なります。

書式指定表示方法値10の表示
%5d右詰め、空白埋め[ 10]
%-5d左詰め、空白埋め[10 ]
%05d右詰め、0埋め[00010]

-フラグは値を左側へ寄せます。0フラグは値を右側へ置き、左側を0で埋めます。

左詰めを指定した場合は、0ではなく空白で埋める形になります。

精度で小数点以下の桁数を指定する

浮動小数点数の精度は、小数点以下を何桁表示するかを指定します。

基本的な書き方は次のとおりです。

%.桁数f

小数点以下2桁なら%.2fを使います。

printf("[%.2f]\n", 12345.678);

実行結果は次のようになります。

[12345.68]

小数点以下3桁目も考慮して、2桁に丸めて表示されます。

精度を変えると、同じ値でも見え方が変わります。

書式指定表示結果
%f12345.678000
%.1f12345.7
%.2f12345.68
%.3f12345.678
%.4f12345.6780

表示が丸められても、変数に保存されている値そのものは変わりません。

フィールド幅と精度を一緒に指定する

フィールド幅と精度は、同じ書式指定の中で組み合わせられます。

printf("[%10.2f]\n", 12345.678);

%10.2fは、次のように読みます。

全体の最小幅  :10文字
小数点以下の桁数:2桁
表示形式    :通常の小数

12345.678を小数点以下2桁にすると、12345.68になります。

12345.68

これは8文字なので、幅10にするため左側に2文字分の空白が入ります。

[  12345.68]

図2:%10.2fを分解して読む

この図から分かること

%10.2fでは、10が表示全体の最小幅、2が小数点以下の桁数、fが通常の小数表記を表します。

まず精度に合わせて12345.68という表示を作り、その結果が幅10より短ければ、左側に空白が追加されます。

文字列にも精度を指定できる

%sにも精度を指定できます。

%.最大表示数s

英字の文字列から先頭5文字を表示する場合は、次のように書きます。

printf("[%.5s]\n", "abcdefg");

実行結果は次のとおりです。

[abcde]

先頭から最大5文字分だけが表示され、それ以降は表示されません。

文字列の精度と浮動小数点数の精度では、意味が異なります。

書式指定精度の意味
%.2f小数点以下を2桁表示
%.5s文字列の先頭から最大5単位分を表示

日本語文字列の精度指定には注意する

printfの%sに対する精度は、狭い文字列では最大バイト数として働きます。

UTF-8の日本語は、一般的に1文字が複数バイトで表現されます。そのため、次のような指定では、日本語を5文字表示できるとは限りません。

printf("%.5s\n", "プログラミング入門");

指定した位置が日本語1文字を構成するバイト列の途中になると、文字が正しく表示されない可能性もあります。

動作を安定して確認する場合は、まず半角英数字の文字列を使うと分かりやすいでしょう。

printf("%.5s\n", "Programming");

Progr

日本語の文字数とバイト数は同じとは限らない、という点を覚えておくと安心です。

フィールド幅・フラグ・精度を確認しよう

ここまでの指定を1つのプログラムにまとめて確認します。

センサー情報を整えて表示するプログラム

ファイル名:5_6_1.c

#include <stdio.h>

int main(void)
{
    int sensor_count = 37;
    unsigned int sensor_code = 37;
    double accuracy = 87.6543;

    /* フィールド幅を確認する */
    printf("フィールド幅の例\n");
    printf("[%-10s]\n", "Sensor");
    printf("[%6d]\n", sensor_count);
    printf("[%10.2f]\n", accuracy);

    /* フラグを確認する */
    printf("\nフラグの例\n");
    printf("左詰め      : [%-6d]\n", sensor_count);
    printf("符号付き    : [%+d]\n", sensor_count);
    printf("16進数表記  : [%#x]\n", sensor_code);
    printf("0埋め6桁    : [%06d]\n", sensor_count);

    /* 精度を確認する */
    printf("\n精度の例\n");
    printf("小数2桁     : [%.2f]\n", accuracy);
    printf("小数4桁     : [%.4f]\n", accuracy);
    printf("英字5文字   : [%.5s]\n", "ControlSystem");

    return 0;
}
実行結果の例
フィールド幅の例
[Sensor    ]
[    37]
[     87.65]

フラグの例
左詰め      : [37    ]
符号付き    : [+37]
16進数表記  : [0x25]
0埋め6桁    : [000037]

精度の例
小数2桁     : [87.65]
小数4桁     : [87.6543]
英字5文字   : [Contr]

変数をデータ型に合わせて用意している

このプログラムでは、3種類の変数を用意しています。

int sensor_count = 37;
unsigned int sensor_code = 37;
double accuracy = 87.6543;

それぞれの変数と書式指定の対応は次のとおりです。

変数データ型使用する書式指定
sensor_countint%d
sensor_codeunsigned int%x
accuracydouble%f

16進数を表示する%xには、unsigned int型のsensor_codeを渡しています。

文字列を左詰めにしている

次のprintfでは、文字列Sensorを幅10で左詰めにしています。

printf("[%-10s]\n", "Sensor");

Sensorは6文字なので、右側に4文字分の空白が入ります。

[Sensor    ]

文字列の項目名を縦に並べるときは、左詰めにすると読みやすくなります。

整数を幅6で右詰めにしている

次のprintfでは、sensor_countを幅6で表示しています。

printf("[%6d]\n", sensor_count);

37は2桁なので、左側に4文字分の空白が入ります。

[    37]

フィールド幅だけを指定したため、右詰めです。

小数に幅と精度を指定している

次のprintfでは、全体幅を10、小数点以下を2桁にしています。

printf("[%10.2f]\n", accuracy);

accuracyの値87.6543は、小数点以下2桁に丸められて87.65になります。

87.65は5文字なので、幅10に合わせて左側に5文字分の空白が入ります。

[     87.65]

#フラグで16進数だと分かるようにしている

次のprintfでは、%#xを使っています。

printf("16進数表記  : [%#x]\n", sensor_code);

37を16進数で表すと25です。#フラグによって先頭に0xが追加されます。

0x25

%xだけで表示した場合は25となります。%#xなら0x25となるため、16進数であることが伝わりやすくなります。

0フラグで6桁にそろえている

次のprintfでは、sensor_countを幅6で0埋めしています。

printf("0埋め6桁    : [%06d]\n", sensor_count);

37は2桁なので、前に0が4つ入ります。

000037

IDや連番のように、一定の桁数で表示したい場合に利用できます。

精度で小数の表示桁数を変えている

同じaccuracyを、異なる精度で表示しています。

printf("小数2桁     : [%.2f]\n", accuracy);
printf("小数4桁     : [%.4f]\n", accuracy);

表示結果は次のとおりです。

87.65
87.6543

書式指定を変更しても、accuracyに保存されている値そのものは変わりません。

英字文字列の先頭5文字を表示している

次のprintfでは、文字列ControlSystemの先頭から最大5文字を表示します。

printf("英字5文字   : [%.5s]\n", "ControlSystem");

実行結果は次のとおりです。

Contr

半角英字は1文字が1バイトなので、精度指定の動作を確認しやすくなります。

書式指定を選ぶ流れ

表示を整えるときは、次の順番で考えると分かりやすいでしょう。

  1. 表示する値のデータ型を確認する
  2. d、f、s、xなどの変換指定子を決める
  3. 必要な最小幅を決める
  4. 左詰めや0埋めなどのフラグを選ぶ
  5. 小数や文字列に必要な精度を指定する
  6. 実行結果を角括弧付きで確認する

たとえば、double型の値を幅8、小数点以下2桁で表示するなら、次のように組み立てます。

double型
  ↓
通常の小数表記なのでf
  ↓
幅8を追加
  ↓
小数点以下2桁を追加
  ↓
%8.2f

図3:目的からprintfの書式指定を組み立てる

この図から分かること

書式指定は、完成形を丸暗記するだけでなく、データ型、フィールド幅、フラグ、精度の順に考えると組み立てやすくなります。

%8.2fなら、幅8と精度2を指定し、最後のfで通常の小数表記を選んでいることが分かります。

よくある間違いを確認しよう

printfの整形指定では、幅と精度の意味を混同しやすいため注意が必要です。

フィールド幅を最大幅だと思ってしまう

次の指定では、整数を最大3桁に制限するわけではありません。

printf("[%3d]\n", 10000);

実行結果では10000がすべて表示されます。

[10000]

フィールド幅は、最低限確保する横幅です。

0埋めと左詰めを混同する

%06dと%-6dは、どちらも幅6ですが、結果が異なります。

printf("[%06d]\n", 58);
printf("[%-6d]\n", 58);

[000058]
[58    ]
書式指定意味
%06d右詰めし、左側を0で埋める
%-6d左詰めし、右側を空白で埋める

幅と精度の位置を逆にする

幅はドットの前、精度はドットの後ろに書きます。

%8.2f
部分意味
8全体の最小幅
.2小数点以下2桁
f通常の小数表記

精度の意味が変換指定子によって変わる

同じ.数字でも、変換指定子によって意味が異なります。

%.2f

浮動小数点数では、小数点以下2桁という意味です。

%.4s

文字列では、先頭から最大4バイト分を表示する指定です。

変換指定子まで含めて意味を確認しましょう。

整形指定を使ってみよう

次の実行結果になるように、空欄へ書式指定を入れてみましょう。

右詰め6桁      : [    73]
左詰め6桁      : [73    ]
符号付き表示   : [+73]
0埋め6桁       : [000073]
16進数を明示   : [0x49]
幅8・小数2桁  : [   12.35]
小数点以下3桁 : [12.346]
先頭4文字      : [form]
printfのフィールド幅・フラグ・精度を練習する問題
#include <stdio.h>

int main(void)
{
    int value = 73;
    unsigned int code = 73;
    double measurement = 12.3456;

    printf("右詰め6桁      : [ ➀ ]\n", value);
    printf("左詰め6桁      : [ ➁ ]\n", value);
    printf("符号付き表示   : [ ➂ ]\n", value);
    printf("0埋め6桁       : [ ➃ ]\n", value);
    printf("16進数を明示   : [ ➄ ]\n", code);
    printf("幅8・小数2桁  : [ ➅ ]\n", measurement);
    printf("小数点以下3桁 : [ ⓻ ]\n", measurement);
    printf("先頭4文字      : [ ➇ ]\n", "format");

    return 0;
}

空欄には次の書式指定が入ります。

空欄書式指定役割
%6d幅6で右詰め
%-6d幅6で左詰め
%+d正の値にもプラス記号を付ける
%06d幅6で0埋め
%#x16進数に0xを付ける
%8.2f幅8、小数点以下2桁
%.3f小数点以下3桁
%.4s文字列の先頭から最大4文字分
フィールド幅・フラグ・精度を使った解答プログラム

ファイル名:5_6_2.c

#include <stdio.h>

int main(void)
{
    int value = 73;
    unsigned int code = 73;
    double measurement = 12.3456;

    printf("右詰め6桁      : [%6d]\n", value);
    printf("左詰め6桁      : [%-6d]\n", value);
    printf("符号付き表示   : [%+d]\n", value);
    printf("0埋め6桁       : [%06d]\n", value);
    printf("16進数を明示   : [%#x]\n", code);
    printf("幅8・小数2桁  : [%8.2f]\n", measurement);
    printf("小数点以下3桁 : [%.3f]\n", measurement);
    printf("先頭4文字      : [%.4s]\n", "format");

    return 0;
}
実行結果の例
右詰め6桁      : [    73]
左詰め6桁      : [73    ]
符号付き表示   : [+73]
0埋め6桁       : [000073]
16進数を明示   : [0x49]
幅8・小数2桁  : [   12.35]
小数点以下3桁 : [12.346]
先頭4文字      : [form]

右詰めと左詰めを使い分けている

右詰めには%6dを使用します。

printf("右詰め6桁      : [%6d]\n", value);

値73は2桁なので、左側に4文字分の空白が入ります。

左詰めには%-6dを使用します。

printf("左詰め6桁      : [%-6d]\n", value);

値の右側に4文字分の空白が入ります。

正の値にプラス記号を付けている

+フラグを使うと、正の値にも符号を付けられます。

printf("符号付き表示   : [%+d]\n", value);

73は正の値なので、+73と表示されます。

0埋めで6桁にそろえている

%06dでは、幅6で空いている部分を0にします。

printf("0埋め6桁       : [%06d]\n", value);

73の前に0が4つ追加され、000073になります。

16進数に0xを付けている

%#xでは、値を小文字の16進数で表示し、先頭に0xを付けます。

printf("16進数を明示   : [%#x]\n", code);

10進数の73は16進数では49なので、0x49と表示されます。

幅8と小数点以下2桁を同時に指定している

%8.2fでは、全体幅を8、小数点以下を2桁にします。

printf("幅8・小数2桁  : [%8.2f]\n", measurement);

12.3456は12.35に丸められます。12.35は5文字なので、左側に3文字分の空白が入ります。

小数点以下3桁に丸めている

%.3fでは、小数点以下を3桁表示します。

printf("小数点以下3桁 : [%.3f]\n", measurement);

12.3456は、表示時に12.346へ丸められます。変数measurementの中身が12.346に書き換えられるわけではありません。

英字文字列の先頭4文字を表示している

%.4sでは、文字列formatの先頭から最大4文字分を表示します。

printf("先頭4文字      : [%.4s]\n", "format");

実行結果はformです。

まずは%5d、%-5d、%05d、%.2f、%8.2fを使って、さまざまな値を表示してみてください。角括弧を付けて実行すると、どこに空白が入ったのかを確認しやすくなります。