見出し画像

いろいろな言語での書式指定子たち#3 - C言語

さて、FORTRANに続きBASICでの書式指定文字列についてまとめてきましたが、今回はお待ちかねのC言語です。C言語の printf などで使われる書式指定子については、まだまだ現役でよくご存知の方も多いですよね。

いろいろな言語での書式指定子たち#2 - BASIC

printf は、書式指定文字列に続いて必要なだけ変数を並べます(実は定数も書ける)。書式指定文字列の中に”%”が出てくると、その後ろに続く文字で指定された書式で値が埋め込まれます。ですから”%”の数と同じだけ変数などを並べないとエラーになるわけです。

%c 文字
%s 文字列
%d (符号付き)整数
%u 符号なし整数
%f 小数

型指定文字

ここまでが基本です。”%”を出力したいときは”%%”とします。それ以外の文字列はそのまま出力されますが、”\”によるエスケープは有効なので、改行コードを”\n”と書くわけです(”\r”などの場合もありますよね)。

整数に関しては

%o 8進数
%x 16進数

10進数以外の表現

という指定もあり、16進数の場合10~15の場合はa~fで表されます。8進や16進表現を指定すると符号無しで解釈されます。このとき%Xと大文字で指定すると10~15をA~Fと大文字で表します。

C言語 printfのフォーマット指定子

フォーマット指定子一覧

それから注意するのが整数よりも大きな値の場合です。long型の場合は指定を怠ると危険な場合があります。もちろんlong long型でも同様です。最近のポピュラーな処理系はint=longで、この問題がバレないのでlong longで確かめます。

#include <stdio.h>
#include <limits.h>

void main() {
  printf("int=%u\t", sizeof(int));
  printf("long=%u\t", sizeof(long));
  printf("long long=%u\n", sizeof(long long));
  long long ll = (long long)INT_MAX + 1;
  printf("%d\n", ll);
  printf("%ld\n", ll);
  printf("%lld\n", ll);
}

int=4 long=4 long long=8
-2147483648
-2147483648
2147483648

出力

このように書式指定でlong(またはlong long)であることを明示的に指定しないと、intであると解釈されて(intを超えた分が捨てられ)正しい値を表示することができません。この長さ指定は元々はlongのlしか無かったのですが、今はかなり増えているようですが主なものだけ挙げます。

%hd short
%ld long
%lld long long

変数のサイズを指定する文字列

小数の場合は、doubleに向かって自動的に変換されるので float であれば困りませんが、long double の時は %L が必要です(大文字小文字の使い分けが難しい)。


ここまでで値を表示することまでは出来るようになったはずですが、ここからが書式指定の本領発揮です。

まずは桁数の指定で[全体の幅].[小数点以下の幅]の指定が出来ます。“[%8.3f]” で 123.456 を表示すれば[ 123.456]となり、”[%8.3e]” で 123.456 を表示すれば[1.235e+02]となります。ちなみに”[%8.3E]で[1.235E+02]です。小数点以下の桁数が3桁である指定が優先されて全体の桁数は指定した8文字をはみ出し9文字になったりします。はみ出したからと言って桁数を調整してくれることもありませんしエラーにもなりません。なお小数点以下の桁数は指定に収めるために値は四捨五入されるので、123.5となります(次の桁が5)。ちなみにこれはVisual Studioの場合でgccだと同じ指定をしてもeまたはEの後ろが3桁となり [123.5e+002] と表示されました。なかなか思い通りになりません。

あまり使ったことはないのですが、この指定は文字列に対しても有効で、全体の幅を使うことで短い文字列は左に空白が補われ、長い場合には切り捨てられるという使い方が出来ます。[%4s] に "123"を当てはめると "[ 123]"、”12345"だとはみ出して"[12345]"になりますが、[%.4s]に"123"だと"[123]"で、"12345"だと"[1234]"という具合です(文字列なので四捨五入ではなくて捨てられる)。

次がゼロ埋め指定で、値が指定した長さより短い時に左側を空白ではなく0で埋める指定です。”[%05d]”で 1 を出力すると [00001] となります。これってバイトを16進ダンプするとき”[%02X]”を良く使います。

そしてここまで文字列を含め何も指定しなければ幅が埋まらなかったときは右詰めでしたが、”-”を付けることで左詰めにすることが出来ます。”abc”を出す時に”[%4s]” で[ abc] ですが、”[%-4s]”だと [abc ]です。ここで”+”を使うと今度は符号の出力で、”[%+5d]”で、-16を出せば [  -16]、16であれば[  +16]となります。マイナスのときだけ表示が崩れるなんて言うことが防げますね。

#include <stdio.h>
void main() {
  printf("[%-5d]\n", 12);
  printf("[%-5d]\n", -12);
  printf("[%-+5d]\n", 12);
  printf("[%-+5d]\n", -12);
}

[12 ]
[-12 ]
[+12 ]
[-12 ]

符号位置を指定

printf出力書式まとめ

printfについてまとめてみた

ここまでが大抵の処理系で使える範囲です。他によく使うのが %p でポインタ型の値を表示する時に使うのですが、具体的にアドレスの長さが何バイトで、どのような形式で表示されるのかは処理系依存です。

#include <stdio.h>
void main() {
  char s[] = "abc";
  printf("%p\n", s);
}

0061FF1C

32ビット環境の場合の例

000000E9250FF9F4

64ビット環境の場合の例

最近の処理系は型指定にうるさくて、char を数値として出すには “%hhd” を使えとか、wchat_t を1文字出すには “%lc” だよとか、size_tは”%z”など長さ指定には厳しいです。小数に関しても e f 以外に g であるとか a というのも追加されていて、いろいろ便利にはなっています。なお、これらの指定は printf またはその仲間たちに対しての説明で、scanf での指定に関しては少し違いがあります(”*”でフィールドを無視するとか[abc]とすると指定した文字のみ取り込まれるという指定が増えていて、”+”であるとか”-”はありません)。

printf

scanf

そしてワイド文字列関連や処理系ごとのローカルな機能もそれなりに充実?しているようで、VisualStudioのヘルプを読むと、実に細かな拡張があるようです。まだ32ビットと64ビット環境は混在していると思うので、どちらでも問題が出ないようにするのは苦労がありますね。

書式指定構文: printf および wprintf 関数

ヘッダ画像は、Copilotの作品です。

#プログラミング言語 #書式 #printf #scanf #C言語


この記事が気に入ったらサポートをしてみませんか?