|
HOME > Linux Tips ( 目次 ) > Linux コマンド 一覧表 > p > printf - ライブラリコールの説明 printf - ライブラリコールの説明 - Linux コマンド集 一覧表名前printf, fprintf, sprintf, snprintf, vprintf, vfprintf, vsprintf, vsnprintf - 指定された書式に変換して出力を行う 書式
#include <stdio.h>
説明printf ()関数グループは、以下で述べるように、 format に従って出力を生成するものである。 printf ()と vprintf ()は出力を stdout (標準出力ストリーム) に書き出す。 fprintf ()と vfprintf ()は出力を指定された出力 stream に書き出す。 sprintf (), snprintf (), vsprintf (), vsnprintf ()は出力を文字列 str に書き込む。 vprintf (), vfprintf (), vsprintf (), vsnprintf ()の各関数はそれぞれ printf (), fprintf (), sprintf (), snprintf (),の各関数と等価であり、可変数引き数の代わりに va_list を 引き数として呼び出される点だけが異なる。 これらの関数では va_end マクロは呼び出されない。 当然、呼び出し後の ap の値は未定義である。 アプリケーションは後で自分で va_end(ap) を呼び出す必要がある。 これらの 8 つの関数は format 文字列の制御に従って出力を書き出す。 format 文字列は、これに続く引き数 (または stdarg (3) の可変長引き数機構を使ってアクセスできる引き数) をどのように変換して出力するかを指定する。 返り値成功時には、上記の関数は書き込まれた文字数を返す (文字列の最後を示すために使用する `\0' は数に含まれない)。 snprintf ()と vsnprintf ()は、 size バイトを越える文字数を書き込まない ( size には文字列の終端にある '\0' もを含まれる)。 この制限によって出力が切り詰められた場合には、 もし十分なスペースがあれば書き込まれたであろう文字の個数 (文字列の終端にある '\0' を除く) を返す。 従って、返り値が size 以上だった場合、出力が切り詰められたことを意味する (後述の注意も参照のこと)。 エラーが発生した場合は、負の数を返す。 フォーマット文字列のフォーマット
フォーマット文字列は文字の列で、
(もしあるなら) 初期シフト状態で始まり、初期シフト状態で終わる。
フォーマット用の文字列は 0 個以上の命令 (directives) によって構成される。
命令には、通常文字と変換指定 (conversion specifications) がある。
通常文字は
%
以外の文字で、出力ストリームにそのままコピーされる。
変換指定は、それぞれが 0 個以上の引き数を取る。
各変換指定は文字
%
で始まり、
"変換指定子 (conversion specifier)"
で終わる。
%
と変換指定子の間には、0 個以上の
フラグ 、
最小
フィールド幅 、
精度 、
長さ修飾子
を (この順序で) 置くことができる。
printf("%*d", width, num);
二番目の書き方では同じ引き数を繰り返し参照することができる。 C99 標準には、 Single Unix Specification 由来の `$' を使った書き方は含まれていない。 `$' を使ったスタイルを使うと、引き数を取る変換及び幅と精度の引き数を 全てこのスタイルで指定しなければならないが、 引き数を消費しない `%%' フォーマットと混ざっているかもしれない。 `$' で指定される引き数の番号に空きがあってはならない。 例えば、もし引き数 1 と 3 が指定されると、引き数 2 もフォーマット文字列のどこかで 指定されなければならない。 数値変換には小数点や 1000 単位の区切り文字を使うものもある。 実際にどの文字を使うかはロケールの LC_NUMERIC による。 POSIX ロケールでは小数点に `.' を用い、 区切り文字は使わない。 従って、 printf("%'.2f", 1234567.89);
は、 POSIX ロケールでは `1234567.89' 、 nl_NL ロケールでは `1234567,89'、 da_DK ロケールでは `1.234.567,89' となる。 フラグ文字% 文字の後ろには 0 個以上のフラグ文字が続く。
フィールド幅最小のフィールド幅を指定する 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 変換のことである。
変換指定子適用される変換の型を指定する文字。 変換指定子とその意味は以下の通りである。
例
日付と時間を `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, ...) {
/* Guess we need no more than 100 bytes. */
int n, size = 100;
char *p, *np;
va_list ap;
if ((p = malloc (size)) == 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);
/* If that worked, return the string. */
if (n > -1 && n < size)
return p;
/* Else try again with more space. */
if (n > -1) /* glibc 2.1 */
size = n+1; /* precisely what is needed */
else /* glibc 2.0 */
size *= 2; /* twice the old size */
if ((np = realloc (p, size)) == NULL) {
free(p);
return NULL;
} else {
p = np;
}
}
}
注意glibc の snprintf ()と vsnprintf ()の実装は、バージョン 2.1 以降は C99 標準に準拠しており、 上記の通りの動作をする。 glibc 2.0.6 までは、出力が切り詰められた場合は -1 を返す。 準拠fprintf (), printf (), sprintf (), vprintf (), vfprintf (), vsprintf ()関数は、C89 と C99 に準拠している。 snprintf ()と vsnprintf ()は C99 に準拠している。 snprintf ()の返り値を見ると、 SUSv2 と C99 標準は互いに矛盾している。 SUSv2 では、 snprintf ()が size =0で呼び出された場合、 1 未満の値を何か返り値とするように規定している。 一方 C99 では、このような場合 str を NULL とし、返り値として (通常通り) 出力バッファが十分な大きさが あった場合に出力されるであろう文字数を返す。 Linux libc4 では、 5 つの C 標準のフラグ、 長さ修飾子 h, l, L 、変換 cdeEfFgGinopsuxX が使える。 但し F は f と同じである。 また、 D, O, U を ld, lo, lu と同じものとして使える (これはまずい仕様で、 後に %D の対応が打ち切られた時に深刻なバグを 引き起こした)。ロケール依存の小数点、1000 区切り、 NaN と無限、 %m$ と *m$ は使えない。 Linux libc5 では、 5 つの C 標準のフラグと ' フラグ、ロケール、 %m$ と *m$ が使える。 また、長さ修飾子 h, l, L, Z, q が使えるが、 L と q は両方とも long double と long long integer に対応している (これはバグである)。 現在では FDOU 変換は認識されないが、変換文字 m が追加された。これは strerror(errno) を出力するものである。 glibc 2.0 では、変換文字 C と S が追加された。 glibc 2.1 では、長さ修飾子 hh, j, t, z と変換文字 a, A が追加された。 glibc 2.2 では、 C99 で規定された意味での変換文字 F と フラグ文字 I が追加された。 歴史Unix V7 では printf (), fprintf (), sprintf ()の 3 つの関数と、フラグ -、幅と精度での *、長さ修飾子 l、 変換 doxfegcsu、そして ld,ld,lu,lx の同義語として D,O,U,X が定義されている。 2.9.1BSD でもこれは同じだったが、 2.10BSD では フラグ #, +, 空白が追加され、 D,O,U,X については記載されなくなった。 2.11BSD では vprintf (), vfprintf (), vsprintf ()が追加され、 D,O,U,X を使わないように警告された。 4.3BSD Reno ではフラグ 0、長さ修飾子 h と L、 変換 n, p, E, G, (現在の意味での) X が追加され、 D,O,U は非推奨扱いとなった。 4.4BSD では、関数 snprintf ()と vsnprintf ()、長さ修飾子 q が導入された。 FreeBSD では、 sprintf ()のために十分なバッファを確保する asprintf ()と vasprintf ()が追加されている。 glibc には、関数 dprintf (), vdprintf ()があり、これらはストリームではなくファイルディスクリプタに出力する。 バグsprintf ()と vsprintf ()は勝手に十分に長い文字列領域があると仮定するので、呼び出し側は 実際の領域からあふれないように注意しなければならない。 しかし、これを保証することが不可能な場合が多い。 生成される文字列の長さはロケール依存であり、予測が難しいことに注意。 代わりに snprintf ()と vsnprintf ()(または asprintf ()と vasprintf ())を使うこと。 Linux libc4.[45] には snprintf ()はないが、 libbsd が提供されており、 その中には sprintf ()と等価な (つまり size 引き数を無視する) snprintf ()がある。 したがって、初期の libc4 で snprintf ()を使うと、深刻なセキュリティ問題を引き起こすことがある。
printf(
foo
);
のようなコードはしばしばバグを引き起こす。
なぜなら
foo
に % 文字が含まれてるかもしれないからである。
foo
が信頼できないユーザー入力から作られている場合には、
その中に %n が含まれていることがあり、
printf
()呼び出し時にメモリへの書き込みが起こり、
セキュリティーホールを作ることになるかもしれない。
関連項目
printf
(1),
asprintf
(3),
dprintf
(3),
scanf
(3),
setlocale
(3),
wcrtomb
(3),
wprintf
(3),
locale
(5)
|
|