Printf

printf（プリントエフ、print formatted）は、C言語の標準入出力ヘッダー (stdio.h) で宣言されている関数である。引数で与えられた書式付きの文字列を、環境によって設定された標準出力 (stdout) に出力する。JIS X 3010:2003においてその機能は「実引数にstdoutを実引数として付加したfprintf関数と等価とする」と規定されている (7.19.6.3)。 この関数は、第1引数に与えられた文字列を出力する。C言語の他の単純な入出力関数に比べ、比較的複雑な構造を持っており、第1引数の文字列のなかで書式を指定することで、第2引数以降の任意の数の引数（可変長引数）を、書式に従って出力することができる。また、整数型（int型）の戻り値を持ち、出力に成功した場合には転送したバイト数、出力に失敗した場合には負数を返却する。 #include <stdio.h> int printf(const char * restrict format, ...); 上記形式における第一引数formatは、それに続く実引数の変換方法を指定する。書式化文字列には、通常のマルチバイト文字または'%'で始まる変換指定のいずれかの指令を0個以上含む。多バイト文字が含まれ、かつ文字コードがシフトシーケンスに依存する場合には、書式化文字列は初期シフト状態で始まり、初期シフト状態で終わらなければならない。書式指定を行う%〜それぞれを書式指定子と呼ぶ。 変換指定は次の形式をとる。（[ ]内は省略可能） %[引数順][フラグ][最小フィールド幅][.精度][長さ修飾子]変換指定子 これは標準C規格の仕様ではなく、POSIXで規定されている拡張である。 書式文字列において%の代わりに%m$を記述することで、続く可変長引数のうちどれを使うかを番号mで指定できる。 例えば、 const char* fmt = "Invalid command %1$s at line %2$d.\n"; const char* cmd = "hoge"; const int lineNumber = 20; printf(fmt, cmd, lineNumber); とした場合、 Invalid command hoge at line 20. と表示される。これだけならば大きな意味はないが、例えばメッセージを翻訳（ローカライズ）する際、 const char* fmt = "%2$d行目のコマンド %1$s は不正です。\n"; というように書式文字列だけをローカライズすることで、可変長引数の指定順を変更せずに、 20行目のコマンド hoge は不正です。 という自然な語順の出力を得ることができる。 変換指定のフラグは以下の通り。 fprintfは、引数にファイルポインタfpが追加され、標準出力の代わりにfpへ出力する変種である。 #include <stdio.h> int fprintf(FILE * restrict fp, const char * restrict format, ...); sprintfとsnprintfは、引数にchar配列の要素へのポインタstrが追加されたもので、標準出力の代わりにstrへ出力する変種である。snprintfは、さらにstrに書き込んで良い文字数を指定する引数が追加されたものであるが、Cの標準規格に収録されたのはC99からである。 #include <stdio.h> int sprintf(char * restrict str, const char * restrict format, ...); int snprintf(char * restrict str, size_t size, const char * restrict format, ...); wprintf, fwprintf, swprintfは、それぞれprintf, fprintf, snprintfに対応し、ワイド文字を使用するものである。sprintfに対応するワイド文字関数（出力バッファサイズを受け取らない関数）は存在しない。 #include <stdio.h> int wprintf(const wchar_t * restrict format, ...); int fwprintf(FILE * restrict fp, const wchar_t * restrict format, ...); int swprintf(wchar_t * restrict str, size_t size, const wchar_t * restrict format, ...); ここまでに挙げたprintfとその変種に対して、可変個引数部分をva_listに変化させた種類が存在する。それぞれ、関数名の頭にvを付けた名称となっている。 #include <stdio.h> int vprintf(const char * restrict format, va_list args); int vfprintf(FILE * restrict fp, const char * restrict format, va_list args); int vsprintf(char * restrict str, const char * restrict format, va_list args); int vsnprintf(char * restrict str, size_t size, const char * restrict format, va_list args); int vwprintf(const wchar_t * restrict format, va_list args); int vfwprintf(FILE * restrict fp, const wchar_t * restrict format, va_list args); int vswprintf(wchar_t * restrict str, size_t size, const wchar_t * restrict format, va_list args); C11のAnnex K Bounds‐checking interfacesで規定された、安全性を向上させた種類が存在する。それぞれ、関数名の末尾に_sを付けた名称となっている。これらの関数は、__STDC_WANT_LIB_EXT1__を1に定義した上で対応するヘッダをインクルードすると宣言される。 #define __STDC_WANT_LIB_EXT1__ 1 #include <stdio.h> #include <wchar.h> int printf_s(const char * restrict format, ...); int fprintf_s(FILE * restrict fp, const char * restrict format, ...); int sprintf_s(char * restrict str, rsize_t size, const char * restrict format, ...); int snprintf_s(char * restrict str, rsize_t size, const char * restrict format, ...); int vprintf_s(const char * restrict format, va_list arg); int vfprintf_s(FILE * restrict fp, const char * restrict format, va_list arg); int vsprintf_s(char * restrict str, rsize_t size, const char * restrict format, va_list arg); int vsnprintf_s(char * restrict str, rsize_t size, const char * restrict format, va_list arg); int wprintf_s(const wchar_t * restrict format, ...); int fwprintf_s(FILE * restrict fp, const wchar_t * restrict format, ...); int swprintf_s(wchar_t * restrict str, rsize_t size, const wchar_t * restrict format, ...); int snwprintf_s(wchar_t * restrict str, rsize_t size, const wchar_t * restrict format, ...); int vwprintf_s(const wchar_t * restrict format, va_list arg); int vfwprintf_s(FILE * restrict fp, const wchar_t * restrict format, va_list arg); int vswprintf_s(wchar_t * restrict str, rsize_t size, const wchar_t * restrict format, va_list arg); int vsnwprintf_s(wchar_t * restrict str, rsize_t size, const wchar_t * restrict format, va_list arg); 以下のような機能が追加されている。 FILE*や文字列の引数（%sに対応する可変長引数部分の引数も含む）に対するNULLポインタチェック %n書式の禁止 #include <stdio.h> int main(void) { int a = 1234; printf("%d %o %x\n", a, a, a); printf("%s %c\n", "abc", 'x'); return 0; } 上記のコードをコンパイルし実行すると、次の出力が得られる。 1234 2322 4d2 abc x 一般に、書式文字列を外部や利用者から自由に指定できる状態とすることはセキュリティホールの温床となるため望ましくない。特に%n書式を用いたものが有名である。 C言語から派生したC++やD言語はもとより、PHP、Ruby、Perlなど他の言語でもprintfが実装されている。また、オブジェクト指向の言語の中には、C++でのBoost::format、Ruby、Pythonなど演算子としてsprintfを実行できるものも存在する。 Unix系オペレーティングシステムのコマンドとして実装されたprintfもある。 ^ 実際のローカライズ作業では、gettext等によってメッセージカタログから文字列を得るようにコードを記述する。 ^ 類似の順序指定可能な書式化機能を持つものとして、Windows APIのFormatMessage()関数や、Microsoft Foundation ClassのAfxFormatString2()関数、.NET FrameworkのSystem.String.Format()メソッドなどが挙げられる。 ^ 可変長引数では「既定の実引数拡張」により、float型の引数はdouble型へと変換されるため、本来はdoubleに対して修飾子を適用する必要はない。 ^ Microsoft Visual C++には非標準関数としてバッファサイズを受け取らないswprintfが存在するが、バージョン2005 (8.0) 以降では既定で無効化されており、非推奨となっている。sprintf、swprintf (CRT), sprintf、_sprintf_l、swprintf、_swprintf_l、__swprintf_l ^ “第10章 著名な脆弱性対策 フォーマット文字列攻撃対策”. IPA ISEC セキュア・プログラミング講座：C/C++言語編. 独立行政法人 情報処理推進機構. 2012年7月3日閲覧。 ^ “PHP: printf”. PHPマニュアル (2013年3月22日). 2013年3月28日閲覧。 ^ “Kernel.#printf”. Ruby1.9.3リファレンスマニュアル. 2013年3月28日閲覧。 ^ “The Boost Format Library” (2006年12月2日). 2013年3月28日閲覧。 ^ “Instance method String#%”. Ruby1.9.3リファレンスマニュアル. 2013年3月28日閲覧。 JIS X 3010:2003 プログラミング言語C N1570 (PDF) （C11の最終ドラフト） C言語 入出力 Hello world scanf 書式文字列攻撃 UNIX コマンド printf(1) man page GNU 版。JM Project printf(1) man page (Solaris 10 Reference Manual) （英語） printf(1) man page（HP-UX リファレンス） 標準 C ライブラリ printf(3) JM Project printf(3C) man page (Solaris 10 Reference Manual) printf(3S) man page（HP-UX リファレンス）