PRINTF(3) | Linux Programmer's Manual | PRINTF(3) |
printf, fprintf, sprintf, snprintf, vprintf, vfprintf, vsprintf, vsnprintf - 指定された書式に変換して出力を行う
#include <stdio.h>
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format,
...);
int sprintf(char *str, const char *format,
...);
int snprintf(char *str, size_t size, const char
*format, ...);
#include <stdarg.h>
int vprintf(const char *format, va_list
ap);
int vfprintf(FILE *stream, const char *format,
va_list ap);
int vsprintf(char *str, const char *format,
va_list ap);
int vsnprintf(char *str, size_t size, const
char *format, va_list ap);
glibc
向けの機能検査マクロの要件
(feature_test_macros(7) 参照):
snprintf(), vsnprintf():
printf() 関数グループは、以下で述べるように、 format に従って出力を生成するものである。 printf() と vprintf() は出力を stdout (標準出力ストリーム) に書き出す。 fprintf() と vfprintf() は出力を指定された出力 stream に書き出す。 sprintf(), snprintf(), vsprintf(), vsnprintf() は出力を文字列 str に書き込む。
snprintf() と vsnprintf() は最大で size バイトを str に書き込む (size には文字列を終端するヌルバイト ('\0') もを含まれる)。
vprintf(), vfprintf(), vsprintf(), vsnprintf() の各関数はそれぞれ printf(), fprintf(), sprintf(), snprintf(), の各関数と等価であり、可変数引き数の代わりに va_list を引き数として呼び出される点だけが異なる。 これらの関数では va_end マクロは呼び出されない。 これらの関数は va_arg を呼び出すので、呼び出し後の ap の値は未定義である。 stdarg(3) を参照のこと。
これらの 8 つの関数は format 文字列の制御に従って出力を書き出す。 format 文字列は、これに続く引き数 (または stdarg(3) の可変長引き数機構を使ってアクセスできる引き数) をどのように変換して出力するかを指定する。
C99 と POSIX.1-2001 では、 sprintf(), snprintf(), vsprintf(), vsnprintf() の呼び出しで、範囲が重複するオブジェクト間でコピーが発生する場合の 結果は不定であると規定されている (例えば、出力先の文字列と入力された 引き数の一つが同じバッファーを参照している場合などである)。 「注意」の節を参照。
成功時には、上記の関数は書き込まれた文字数を返す (文字列の最後を示すために使用するヌルバイトは数に含まれない)。
snprintf() と vsnprintf() は、 size バイトを越える文字数を書き込まない (size には文字列を終端するヌルバイト ('\0') も含まれる)。 この制限によって出力が切り詰められた場合には、 もし十分なスペースがあれば書き込まれたであろう文字の個数 (文字列を終端するヌルバイトを除く) を返す。 従って、返り値が size 以上だった場合、出力が切り詰められたことを意味する (後述の注意も参照のこと)。
エラーが発生した場合は、負の数を返す。
フォーマット文字列は文字の列で、 (もしあるなら) 初期シフト状態で始まり、初期シフト状態で終わる。 フォーマット用の文字列は 0 個以上の命令 (directives) によって構成される。 命令には、通常文字と変換指定 (conversion specifications) がある。 通常文字は % 以外の文字で、出力ストリームにそのままコピーされる。 変換指定は、それぞれが 0 個以上の引き数を取る。 各変換指定は文字 % で始まり、 変換指定子 (conversion specifier) で終わる。 % と変換指定子の間には、0 個以上の フラグ 、 最小 フィールド幅 、 精度 、 長さ修飾子 を (この順序で) 置くことができる。
引き数は
(型の格上げの後は)
変換指定子が表す型と正確に対応しなければならない。
デフォルトでは、'*'
や変換指定子が出てくる毎に次の引き数を要求され、
引き数は指定された順序で使用されていく
(指定された引き数の個数が不十分ならエラーとなる)。
また、引き数が必要な箇所で
'%' の代わりに "%m$"、
'*'の代わりに "*m$"
と書くことで、
明示的にどの引き数を使用するかを指定することもできる。
ここで 10進の整数 m
は希望の引き数の引き数リストでの位置を示す
(最初の引き数の番号が
1 である)。 従って、
printf("%*d", width, num);
printf("%2$*1$d", width, num);
は等価である。 二番目の書き方では同じ引き数を繰り返し参照することができる。 C99 標準には、 Single UNIX Specification 由来の '$' を使った書き方は含まれていない。 '$' を使ったスタイルを使うと、引き数を取る変換及び幅と精度の引き数を 全てこのスタイルで指定しなければならないが、 引き数を消費しない "%%" フォーマットと混ざっているかもしれない。 '$' で指定される引き数の番号に空きがあってはならない。 例えば、もし引き数 1 と 3 が指定されると、引き数 2 もフォーマット文字列のどこかで 指定されなければならない。
数値変換には小数点や
1000
単位の区切り文字を使うものもある。
実際にどの文字を使うかはロケールの
LC_NUMERIC による。 POSIX
ロケールでは小数点に
'.' を用い、
区切り文字は使わない。
従って、
printf("%'.2f", 1234567.89);
% 文字の後ろには 0 個以上のフラグ文字が続く。
上記の 5 つのフラグは C99 標準で定義されている。 Single UNIX Specified では、さらにもう一つフラグ文字が規定されている。
glibc 2.2 では、さらに一つフラグ文字が追加されている。
最小のフィールド幅を指定する 10進数の数値文字列 (文字列の最初の文字は ゼロ以外)。本項目はオプションである。 変換された値の文字数がフィールド長よりも少ない場合、 フィールドの左側をスペースで埋める (左揃えのフラグがある場合は右側を埋める)。 10進数の文字列の代わりに "*" や "*m$" (m は 10進整数) を書くこともできる。 "*" と "*m$" はそれぞれ、次の引き数と m 番目の引き数をフィールド幅として 使うことを指定する (これらの引き数は int 型でなければならない)。 フィールド幅に負の数が指定された場合は、 '-' フラグと正の数のフィールド幅として扱われる。 フィールド幅が小さかったり指定がなかったりしても、フィールドが切り詰められる ことはない。もし変換結果がフィールド幅よりも広かった場合、 フィールドは変換結果が入る幅に広げられる。
オプションである精度は、ピリオド ('.') とそれに続く10進数という 形式で指定する (10進数はオプション) 。 10進数の文字列の代わりに "*" や "*m$" (m は 10 進整数)を書くこともできる。 "*" と "*m$" はそれぞれ、次の引き数と m 番目の引き数を精度として 使うことを指定する (これらの引き数は int 型でなければならない)。 精度として '.' だけが指定された場合、 精度はゼロとみなされる。 精度が負の数だった場合、 精度は指定されなかったものとみなされる。 d, i, o, u, x, X 変換では、表示される最小の桁数を指定する。 a, A, e, E, f, F 変換では、小数点以下に表示される数字の桁数を指定する。 g と G 変換では、有効数字の最大桁数を指定する。 s と S 変換では、文字列から出力される最大文字数を指定する。
「整数変換」とは、 d, i, o, u, x, X 変換のことである。
SUSv3 では上記のすべてが規定されている。 SUSv2 で規定されていたのは、 長さ修飾子 h (hd, hi, ho, hx, hX, hn), l (ld, li, lo, lx, lX, ln, lc, ls), L (Le, LE, Lf, Lg, LG) だけであった。
適用される変換の型を指定する文字。 変換指定子とその意味は以下の通りである。
(SUSv2 では、F は規定されておらず、無限や NaN に関する文字列表現を行ってもよいことになっている。 SUSv3 では F の規定が追加された。 C99 標準では、f 変換では、無限は "[-]inf" か "[-]infinity" と表示し、 NaN は文字列の先頭に `nan' をつけて表示するように規定されている。 F 変換の場合は "[-]INF", "[-]INFINITY", "NAN*" と表示される。)
l 修飾子が指定されている場合、 引き数は const wchar_t * 型でワイド文字の配列へのポインターであることが期待されている。 配列中のワイド文字は (1文字毎に wcrtomb(3) を呼び出して) マルチバイト文字に変換される (最初のワイド文字の変換の前に wcrtomb() のシフト状態を初期状態に戻してから変換は行われる)。 マルチバイト文字への変換は、文字列を終端するヌルワイド文字が 出てくるまで行われ、終端ヌルワイド文字も含めて変換される。 結果のマルチバイト文字列は、終端のヌルバイトが出てくるまで 出力される (終端のヌルバイトは出力されない)。 精度が指定された場合、指定されたバイト数以上には出力されない。 但し、マルチバイト文字の一部分だけが出力されることはない。 精度は「バイト」数を指定するものであり、「ワイド文字」数や 「画面での位置」を指定するものではないことに注意。 精度が指定されていて、さらに出力が配列の末尾に達する前に出力バイト数が 精度の値を超える場合だけは、配列はヌルワイド文字で終端されていなくてもよい。 それ以外の場合は、必ず配列はヌルワイド文字で終端されていなければならない。
fprintf(), printf(), sprintf(), vprintf(), vfprintf(), vsprintf() 関数は、C89 と C99 に準拠している。 snprintf() と vsnprintf() は C99 に準拠している。
snprintf() の返り値を見ると、 SUSv2 と C99 標準は互いに矛盾している。 SUSv2 では、 snprintf() が size=0 で呼び出された場合、 1 未満の値を何か返り値とするように規定している。 一方 C99 では、このような場合 str を NULL とし、返り値として (通常通り) 出力バッファーが十分な大きさが あった場合に出力されるであろう文字数を返す。 SUSv3 やそれ以降では C99 の snprintf() の規定にあわせたものとなっている。
glibc 2.1 では、長さ修飾子 hh, j, t, z と変換文字 a, A が追加された。
glibc 2.2 では、 C99 で規定された意味での変換文字 F と フラグ文字 I が追加された。
テキストを buf に追加するのに、軽率にも次のようなコードを使っているプログラムがある。
sprintf(buf, "%s some further text", buf);
しかしながら、標準規格では、 sprintf(), snprintf(), vsprintf(), vsnprintf() の呼び出しにおいて、コピー元とコピー先のバッファーが重なっていた場合の 結果は不定である、と明記されている。 使用する gcc(1) のバージョンや指定したコンパイラのオプション次第では、 上記のような呼び出しで、期待した結果が得られ「ない」ことがある。
glibc の snprintf() と vsnprintf() の実装は、バージョン 2.1 以降は C99 標準に準拠しており、 上記の通りの動作をする。 glibc 2.0.6 までは、出力が切り詰められた場合は -1 を返す。
sprintf() と vsprintf() は勝手に十分に長い文字列領域があると仮定するので、呼び出し側は 実際の領域からあふれないように注意しなければならない。 しかし、これを保証することが不可能な場合が多い。 生成される文字列の長さはロケール依存であり、予測が難しいことに注意。 代わりに snprintf() と vsnprintf() (または asprintf(3) と vasprintf(3)) を使うこと。
printf(foo); のようなコードはしばしばバグを引き起こす。 なぜなら foo に % 文字が含まれてるかもしれないからである。 foo が信頼できないユーザー入力から作られている場合には、 その中に %n が含まれていることがあり、 printf() 呼び出し時にメモリーへの書き込みが起こり、 セキュリティーホールを作ることになるかもしれない。
Pi を 5
桁で出力する。
#include <math.h> #include <stdio.h> fprintf(stdout, "pi = %.5f\n", 4 * atan(1.0));
日付と時間を "Sunday,
July 3, 10:02"
の形式で出力する。
(weekday と month
は文字列へのポインターである)
#include <stdio.h> fprintf(stdout, "%s, %s %d, %.2d:%.2d\n", weekday, month, day, hour, min);
日 - 月 - 年
の順序で表示を行う国も多い。
従って、国際版では書式で指定された順番で
引き数を表示できなければならない。
#include <stdio.h> fprintf(stdout, format, weekday, month, day, hour, min);
format
はロケールに依存しており、引き数の順番を変えることもできる。
format が
"%1$s, %3$d. %2$s, %4$d:%5$.2d\n"
であれば、 "Sonntag, 3. Juli, 10:02" という結果になる。
十分に大きな文字列領域を確保して、そこにメッセージを格納するには (glibc 2.0 と glibc 2.1 の両方で正しく動作するコード):
#include <stdio.h> #include <stdlib.h> #include <stdarg.h> char * make_message(const char *fmt, ...) {
int n;
int size = 100; /* Guess we need no more than 100 bytes */
char *p, *np;
va_list ap;
p = malloc(size);
if (p == NULL)
return NULL;
while (1) {
/* Try to print in the allocated space */
va_start(ap, fmt);
n = vsnprintf(p, size, fmt, ap);
va_end(ap);
/* Check error code */
if (n < 0) {
free(p);
return NULL;
}
/* If that worked, return the string */
if (n < size)
return p;
/* Else try again with more space */
size = n + 1; /* Precisely what is needed */
np = realloc(p, size);
if (np == NULL) {
free(p);
return NULL;
} else {
p = np;
}
} }
バージョン 2.0.6 より前の glibc で切り詰めが起こった場合、切り詰めは適切に処理されず、エラーとして扱われる。
printf(1), asprintf(3), dprintf(3), scanf(3), setlocale(3), wcrtomb(3), wprintf(3), locale(5)
この man ページは Linux man-pages プロジェクトのリリース 3.79 の一部 である。プロジェクトの説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。
2014-07-08 | GNU |