
printf は、テキストをフォーマットして標準出力に書き込むC 標準ライブラリ 関数です。
printfという名前はprint formattedの略で、print はプリンタへの出力を指しますが、機能はプリンタ出力に限定されません。
標準ライブラリには、printf のような関数のファミリーを形成する他の多くの同様の関数が用意されています。これらの関数は、書式文字列パラメータと、関数が書式文字列ごとにシリアル化して出力ストリームまたは文字列バッファに書き込む可変数の値パラメータを受け入れます。
書式文字列は、逐語的なテキストと、値をシリアル化する方法を指定する書式指定子で構成されるテンプレート言語としてエンコードされます。書式文字列は左から右に処理され、見つかった書式指定子ごとに後続の値が使用されます。書式指定子は文字で始まり、値をシリアル化する方法を指定する 1 つ以上の文字が続きます。
%
フォーマット文字列の構文とセマンティクスは、printf のようなファミリのすべての関数で同じです。
フォーマット指定子と値の数および型が一致しないと、クラッシュや脆弱性が発生する可能性があります。
printf フォーマット文字列は、フォーマットされた入力 (字句解析とも呼ばれる) を提供するscanfフォーマット文字列を補完するものです。どちらのフォーマット文字列も、他のテンプレート エンジン、字句解析器、パーサーと比較すると、比較的シンプルな機能を提供します。
フォーマット設計は他のプログラミング言語にもコピーされています。
歴史
1950年代: Fortran
Fortranのような初期のプログラミング言語では、他の計算とは異なる構文を持つ特別なステートメントを使用して、書式設定の記述を構築していました。[1]この例では、書式は601行目に指定されており、PRINT [a]コマンドは行番号でそれを参照しています。
印刷601 、IA 、IB 、面積601フォーマット( 4 H A = 、I5、5 H B = 、I5、8 H面積= 、F10 . 2、13 H正方形単位)
ここに:
4H4文字の文字列を示します" A= "(ホレリス体Hを意味します)。I5幅 5 の整数フィールドを示します。F10.2幅 10、小数点以下 2 桁の浮動小数点フィールドを示します。
入力引数 100、200、および 1500.25 を使用した出力は次のようになります。
A= 100 B= 200 面積= 1500.25 平方単位
1960年代: BCPLとALGOL 68
1967年にBCPLが登場しました。[2]そのライブラリにはwritefルーチンが含まれていました。[3]サンプルアプリケーションは次のようになります。
WRITEF("%I2-QUEENS問題には%I5個の解があります*N", NUMQUEENS, COUNT)
ここに:
%I2幅 2 の整数を示します (書式指定のフィールド幅と型の順序は C のものと逆になりますprintf)。%I5幅5の整数を示します。*Nは、改行文字を表すBCPL言語のエスケープ シーケンスです (C ではエスケープ シーケンスが使用されます\n)。
1968 年、ALGOL 68 はより関数に似たAPI を備えていましたが、特殊な構文 ($区切り文字で特殊な書式設定構文を囲む) がまだ使用されていました。
printf (( $ "色 " g ", number1 " 6 d , ", number2 " 4 zd , ", 16進数 " 16 r2d , ", float " - d .2 d , ", unsigned value" -3 d "." l$ ,
"赤" , 123456 , 89 , BIN 255 , 3.14 , 250 ));
Fortran とは対照的に、通常の関数呼び出しとデータ型を使用すると、言語とコンパイラが簡素化され、同じ言語で入出力の実装を記述できるようになります。これらの利点は欠点 (多くの場合、型の安全性が完全に欠如しているなど) を上回り、ほとんどの新しい言語では I/O は構文の一部ではありません。
1970年代: C
1973年に、はバージョン4 Unixの一部としてCprintfルーチンとして組み込まれました。[4]
1990年代: シェルコマンド
1990年に、4.3BSD-Renoprintfの一部としてシェルコマンドが証明されました。これは標準ライブラリ関数をモデルにしています。[5]
1991 年に、printfコマンドが GNU shellutils (現在はGNU Core Utilitiesの一部) にバンドルされました。
書式指定子
値の書式設定は、書式文字列のマークアップとして指定されます。たとえば、次の出力では、「あなたの年齢は」に続いて変数の値がage10 進形式で出力されます。
printf ( "あなたの年齢は%dです" , age );
構文
フォーマット指定子の構文は次のとおりです。
%[パラメータ][フラグ][幅][精度][長さ]タイプ
パラメータフィールド
パラメータ フィールドはオプションです。含まれている場合、指定子と値の一致は連続的ではありません。数値nは、n番目の値パラメータを選択します。
このフィールドを使用すると、値を複数回渡す代わりに、フォーマット文字列で同じ値を複数回使用できます。指定子にこのフィールドが含まれている場合は、後続の指定子にもこのフィールドが含まれている必要があります。
例えば、
printf ( "%2$d %2$#x; %1$d %1$#x" 、16 、17 )
出力: 17 0x11; 16 0x10.
このフィールドは、異なる語順を使用することが多い さまざまな自然言語にメッセージをローカライズする場合に特に役立ちます。
Microsoft Windows では、この機能は別の関数を介してサポートされますprintf_p。
フラグフィールド
フラグ フィールドには、次の 0 個以上の値 (任意の順序) を指定できます。
幅フィールド
幅フィールドは、出力する最小文字数を指定します。値をより少ない文字数で表せる場合は、出力が指定された文字数になるように、値の左側にスペースが埋め込まれます。値にさらに多くの文字数が必要な場合は、出力が指定された幅よりも長くなります。値が切り捨てられることはありません。
たとえば、幅を 3 に指定し、左側にスペースを入れて 3 文字を出力します。指定された幅は 3 ですが、その値の最小幅は 4 文字なので、呼び出しは4 文字を出力します。
printf("%3d", 12) 12printf("%3d", 1234)1234
幅フィールドが省略されている場合、出力は値の最小文字数になります。
フィールドが として指定されている場合*、幅の値は呼び出し内の値のリストから読み取られます。[6]たとえば、出力では、2番目のパラメータ3が幅(*と一致)であり、10がシリアル化する値(dと一致)です。
printf("%*d", 3, 10) 10
-幅フィールドの一部ではありませんが、先頭のゼロは上記のゼロパディング フラグとして解釈され、負の値は、同じく上記の
左揃えフラグと組み合わせて正の値として扱われます。
幅フィールドは、値をテーブル (表形式の出力) としてフォーマットするために使用できます。ただし、指定された幅に収まる値より大きい値がある場合、列は整列されません。たとえば、最後の行の値 (1234) は幅 3 の最初の列に収まらないため、列が整列されていないことに注意してください。
1 1 12 12 123 123 1234 123
精密フィールド
精度フィールドは通常、特定の書式設定タイプに応じて、出力の最大限度を指定します。浮動小数点数値型の場合、出力を丸める小数点の右側の桁数を指定します。文字列型の場合、出力される文字数を制限し、それを超えると文字列は切り捨てられます。
精度フィールドは省略することも、数値の整数値にすることも、アスタリスクで示されて別の引数として渡される動的な値にすることもできます*。たとえば、出力は次のようになります。printf("%.*s", 3, "abcdef")アブ。
長さフィールド
長さフィールドは省略することも、次のいずれかにすることもできます。
ISO C99 拡張機能が広く使用されるようになる前に、次のようなプラットフォーム固有の長さオプションが存在していました。
ISO C99 には、inttypes.hプラットフォームに依存しないコーディング用のマクロが多数含まれたヘッダー ファイルが含まれていますprintf。たとえば、64 ビットの符号付き整数の 10 進形式を指定します。マクロは文字列リテラルに評価され、コンパイラは隣接する文字列リテラルを連結するため、式は 1 つの文字列にコンパイルされます。
printf("%" PRId64, t);"%" PRId64
マクロには以下が含まれます:
タイプフィールド
タイプ フィールドは次のいずれかになります。
カスタムデータ型の書式設定
カスタム データ型を使用して書式設定を処理する一般的な方法は、カスタム データ型の値を文字列に書式設定し、%s指定子を使用してシリアル化された値をより大きなメッセージに含めることです。
一部の printf のような関数では、エスケープ文字ベースのミニ言語の拡張が許可されているため、プログラマは非組み込み型に対して特定の書式設定関数を使用できます。1 つは (現在は非推奨) glibcの register_printf_function() です。ただし、静的書式文字列チェックと競合するため、ほとんど使用されません。もう 1 つは Vstr カスタム フォーマッタで、これにより複数文字の書式名を追加できます。
一部のアプリケーション ( Apache HTTP Serverなど) には、独自の printf のような関数が含まれており、拡張機能が組み込まれています。ただし、これらはすべて、 と同じ問題を抱えている傾向がありますregister_printf_function()。
Linuxカーネル 関数は、追加のフォーマット文字を付加するprintkことで、汎用%p仕様を使用してカーネル構造を表示するさまざまな方法をサポートしています。 [11]たとえば、はIPv4アドレスをドット付き10進数形式で出力します。これにより、通常のprintfとの完全な互換性を犠牲にして、
(その部分の)静的フォーマット文字列チェックが可能になります。%pI4%p
家族
のバリアントはprintf書式設定機能を提供しますが、動作が追加されたり、わずかに異なったりします。
fprintf標準出力以外の出力を許可するシステム ファイル オブジェクトに出力します。
sprintf標準出力ではなく文字列バッファに書き込みます。
snprintfsprintf呼び出し元がバッファに書き込む最大文字数を指定する長さ (n) パラメータを提供するため、
より高いレベルの安全性が提供されます。
ほとんどの printf ファミリ関数には、可変長パラメータ リストではなく を受け入れるバリアントがありますva_list。たとえば、vfprintf、vsprintfなどがありますvsnprintf。
脆弱性
フォーマット文字列攻撃
余分な値パラメータは無視されますが、渡された値パラメータよりも多くの書式指定子が書式文字列に含まれている場合 、動作は未定義になります。一部の C コンパイラでは、余分な書式指定子があると、値がなくても値が消費されます。これにより、書式文字列攻撃が発生する可能性があります。一般に、C では、引数はスタックで渡されます。渡される引数が少なすぎると、printf はスタックフレームの末尾を超えて読み取ることができ、攻撃者がスタックを読み取ることができるようになります。
GNU コンパイラ コレクションなどの一部のコンパイラは、printf のような関数の書式文字列を静的にチェックし、問題について警告します (フラグ-Wallまたはを使用する場合)。GCC は、関数に
-Wformat非標準の「フォーマット」が適用されている場合、ユーザー定義の printf スタイル関数についても警告します。__attribute__
制御されていない書式文字列の悪用
フォーマット文字列は多くの場合、文字列リテラルであり、関数呼び出しの静的分析が可能です。ただし、フォーマット文字列は変数の値である可能性があり、動的なフォーマットが可能になりますが、制御されていないフォーマット文字列の悪用と呼ばれるセキュリティ上の脆弱性も発生します。
メモリ書き込み
表面的には出力関数ですが、printf引数で指定されたメモリ位置に を介して書き込むことができます%n。この機能は、より複雑な書式文字列攻撃の一部として時々使用されます。[12]
この機能は、適切に形成された引数セットであっても、偶然にチューリング完全になること%nもあります。フォーマット文字列で記述された三目並べのゲームは、第27回IOCCCの優勝作品です。[13]printf
printf を使用したプログラミング言語
printf または printf のような機能を備えた注目すべきプログラミング言語。
この記事のスタイルから外れた書式文字列を使用する言語 ( AMPLやElixirなど)、 JVMまたはその他の環境から実装を継承する言語( ClojureやScalaなど)、標準のネイティブ printf 実装はないが printf の動作をエミュレートする外部ライブラリを持つ言語 ( JavaScriptなど) は除外されます。
- アーク[14]
- C
- C++
- だ
- ファ#
- G (ラボビュー)
- GNU 数学プログ
- GNU オクターブ
- 行く
- ハスケル
- J
- Java (バージョン 1.5 以降) および JVM 言語
- Julia(Printf標準ライブラリ経由[15])
- Lua (文字列.形式)
- メープル
- マテリアライズド
- Max (sprintf オブジェクト経由)
- ミスリル
- オブジェクティブC
- OCaml (Printf モジュール経由)
- パリ/GP
- パール
- PHP の
- Python(
%演算子経由)[16] - R
- 楽(
printf、、sprintfおよび経由fmt) - 赤/システム
- ルビー
- Tcl (format コマンド経由)
- Transact-SQL (xp_sprintf 経由)
- Vala (経由
print()およびFileStream.printf())
参照
- フォーマット (Common Lisp)
- C標準ライブラリ
- フォーマット文字列攻撃
iostream- ML(プログラミング言語)
- printf デバッグ
printf(Unix)printk(カーネルメッセージを出力)scanf- 文字列補間
注記
参考文献
- ^ ab Backus, John Warner ; Beeber, RJ; Best, Sheldon F.; Goldberg, Richard ; Herrick, Harlan L.; Hughes, RA; Mitchell, LB; Nelson, Robert A.; Nutt, Roy ; Sayre, David ; Sheridan, Peter B.; Stern, Harold; Ziller, Irving (1956年10月15日). Sayre, David (ed.). The FORTRAN Automatic Coding System for the IBM 704 EDPM: Programmer's Reference Manual (PDF) . New York, USA: Applied Science Division and Programming Research Department, International Business Machines Corporation . pp. 26–30. 2022年7月4日時点のオリジナルよりアーカイブ(PDF) . 2022年7月4日閲覧。(2+51+1ページ)
- ^ “BCPL”. cl.cam.ac.uk . 2018年3月19日閲覧。
- ^ Richards, Martin; Whitby-Strevens, Colin (1979). BCPL - 言語とそのコンパイラ。ケンブリッジ大学出版局。p. 50。
- ^ McIlroy, MD (1987). A Research Unix reader: annotated excerpts from the Programmer's Manual, 1971–1986 (PDF) (技術レポート). CSTR. Bell Labs. 139.
- ^ "printf (4.3+Reno BSD)". man.freebsd.org . 2024年4月1日閲覧。
- ^ "printf". cplusplus.com . 2020年6月10日閲覧。
- ^ ISO / IEC (1999)。ISO/IEC 9899:1999(E): プログラミング言語 – C §7.19.6.1 パラ 7。
- ^ 「GNU C ライブラリリファレンスマニュアル」、「12.12.3 出力変換表」。Gnu.org。2014年3 月 17 日閲覧。
- ^ "printf" ( %a はC99 で追加されました)
- ^ 「数値印刷出力のフォーマット」。Javaチュートリアル。Oracle Inc. 2018 年3 月 19 日閲覧。
- ^ 「Linux kernel Documentation/printk-formats.txt」。Git.kernel.org。2015年4月29日時点のオリジナルよりアーカイブ。 2014年3月17日閲覧。
- ^ https://www.exploit-db.com/docs/english/28476-linux-format-string-exploitation.pdf [単なる URL PDF ]
- ^ 「Best of show – abuse of libc」 Ioccc.org . 2022年5月5日閲覧。
- ^ 「The Open Group Base Specifications Issue 7、2018年版」、「POSIX awk」、「出力ステートメント」。pubs.opengroup.org 。2022年5月29日閲覧。
- ^ 「Printf 標準ライブラリ」。Julia言語マニュアル。2021年2 月 22 日閲覧。
- ^ 「組み込み型: printf スタイルの文字列フォーマット」、Python 標準ライブラリ、Python Software Foundation 、 2021 年2 月 24 日閲覧
外部リンク
- std::fprintf の C++ リファレンス
- gcc printf フォーマット仕様クイックリファレンス
- : フォーマットされた出力を印刷します – The Open GroupのSystem Interfaces Reference、The Single UNIX Specificaion、バージョン 4
- Java 1.5 のフォーマッタ仕様
- GNU Bash printf(1) 組み込み
