コンテンツにスキップ
Wikipedia

printf

出典: フリー百科事典『ウィキペディア(Wikipedia)』

printf(プリントエフ)は、C言語標準ライブラリに属し、ヘッダーファイル stdio.h で宣言されている関数である。引数で与えられた書式付きの文字列を、環境によって設定された標準出力 (stdout) に出力する。その機能は国際標準規格「ISO/IEC 9899:1999」(通称C99)および日本産業規格(旧称・日本工業規格)による翻訳「JIS X 3010:2003」においてprintf関数は,与えられた実引数の前にstdoutを実引数として付加したfprintf関数と等価とする。と規定されている (7.19.6.3)。

この関数は、第1引数に与えられた文字列を出力する。C言語の他の単純な入出力関数に比べ、比較的複雑な構造を持っており、第1引数の文字列のなかで書式を指定することで、第2引数以降の任意の数の引数(可変長引数)を、書式に従って出力することができる。また、整数型(int型)の戻り値を持ち、出力に成功した場合には転送したバイト数、出力に失敗した場合には負数を返却する。

形式

[編集 ]
#include<stdio.h>
intprintf(constchar*restrictformat,...);

書式化文字列

[編集 ]

上記形式における第一引数には、それに続く実引数の変換方法を指定する。書式化文字列には、通常のマルチバイト文字または%で始まる変換指定のいずれかの指令を0個以上含む。マルチバイト文字が含まれ、かつ文字コードシフトシーケンスに依存する場合には、書式化文字列は初期シフト状態で始まり、初期シフト状態で終わらなければならない。書式指定を行う%それぞれを書式指定子と呼ぶ。

変換指定

[編集 ]

変換指定は次の形式をとる。([ ]内は省略可能)

%[引数順][フラグ][最小フィールド幅][.精度][長さ修飾子]変換指定子

引数順 (POSIX)

[編集 ]

これは標準C規格の仕様ではなく、POSIXで規定されている拡張である。

書式文字列において%の代わりに%m$を記述することで、続く可変長引数のうちどれを使うかを番号mで指定できる。 例えば、

constchar*fmt="Invalid command %1$s at line %2$d.\n";
constchar*cmd="hoge";
constintlineNumber=20;
printf(fmt,cmd,lineNumber);

とした場合、

Invalid command hoge at line 20.

と表示される。これだけならば大きな意味はないが、例えばメッセージを翻訳(ローカライズ)する際、

constchar*fmt="%2$d行目のコマンド %1$s は不正です。\n";

というように書式文字列だけをローカライズする[注釈 1] ことで、可変長引数の指定順を変更せずに、

20行目のコマンド hoge は不正です。

という自然な語順の出力を得ることができる[注釈 2]

フラグ

[編集 ]

変換指定のフラグは以下の通り。

フラグ 意味
- フィールドの左寄せ
+ 常に符号を出力
空白 数値が正または 0 の場合は符号の代わりに空白を出力
# 代替形式。基数を表すプレフィックスの出力等
0 出力文字数が最小フィールド幅未満の場合は'0'を出力

長さ修飾子

[編集 ]
修飾子 意味 導入バージョン
hh 実引数はchar C99以降
h 実引数はshort 全バージョン
l(エル) 実引数はlong型、wint_t型、wchar_t型またはdouble[注釈 3] wint_tおよびwchar_tについてはC95以降、doubleについてはC99以降
ll(エルエル) 実引数はlonglong C99以降
j 実引数はintmax_t C99以降
z 実引数はsize_t C99以降
t 実引数はptrdiff_t C99以降
L 実引数はlongdouble 全バージョン

なお、C99で追加されたint32_tint64_tなどのビット数が指定された整数型の実引数に対して、これらの長さ修飾子を直接使用した場合の動作は未定義である。仮に特定の実装では期待通り動作したとしても、データ型モデルによっては移植の際に非互換が生じることもある[注釈 4] 。これらの固定幅の整数型を実引数として使用する際は、明示的な型キャストをするか、inttypes.hヘッダーに定義されているPRIで始まるマクロを利用する必要がある[1] [2]

変換指定子

[編集 ]
指定子 意味 導入バージョン
d, i 10進符号付き整数 全バージョン
u 10進符号無し整数 全バージョン
o 8進符号無し整数 全バージョン
x, X 16進符号無し整数( X は大文字で出力) 全バージョン
e, E 指数形式浮動小数点数( E は大文字で出力) 全バージョン
f, F 小数形式浮動小数点数( F は大文字で出力) 全バージョン
g, G e または f 形式のうち適した方( G は大文字で出力) 全バージョン
a, A 16進浮動小数点( A は大文字で出力) C99以降
c 文字 全バージョン
s 文字列 全バージョン
p ポインタの値 全バージョン
n 整数変数に出力済み文字数を格納 全バージョン
% '%'の出力 全バージョン

関連する関数

[編集 ]

fprintf

[編集 ]

fprintfは、引数にファイルポインタfpが追加され、標準出力の代わりにfpへ出力する変種である。

#include<stdio.h>
intfprintf(FILE*restrictfp,constchar*restrictformat,...);

sprintf, snprintf

[編集 ]

sprintfとsnprintfは、引数にchar配列の要素へのポインタstrが追加されたもので、標準出力の代わりにstrへ出力する変種である。snprintfは、さらにstrに書き込んで良い文字数を指定する引数が追加されたものであるが、Cの標準規格に収録されたのはC99からである。

#include<stdio.h>
intsprintf(char*restrictstr,constchar*restrictformat,...);
intsnprintf(char*restrictstr,size_tsize,constchar*restrictformat,...);

wprintf, fwprintf, swprintf

[編集 ]

wprintf, fwprintf, swprintfは、それぞれprintf, fprintf, snprintfに対応し、ワイド文字を使用するものである。C95で標準化された。sprintfに直接対応するワイド文字バージョンの関数(出力バッファサイズを受け取らない関数)は存在しない[注釈 5]

#include<stdio.h> /* または wchar.h */
intwprintf(constwchar_t*restrictformat,...);
intfwprintf(FILE*restrictfp,constwchar_t*restrictformat,...);
intswprintf(wchar_t*restrictstr,size_tsize,constwchar_t*restrictformat,...);

va_listを引数に取るもの

[編集 ]

ここまでに挙げたprintfとその変種に対して、可変個引数部分をva_listに変化させた種類が存在する。それぞれ、関数名の頭にvを付けた名称となっている。vsnprintfはC99で標準化された。

#include<stdio.h>
intvprintf(constchar*restrictformat,va_listargs);
intvfprintf(FILE*restrictfp,constchar*restrictformat,va_listargs);
intvsprintf(char*restrictstr,constchar*restrictformat,va_listargs);
intvsnprintf(char*restrictstr,size_tsize,constchar*restrictformat,va_listargs);
#include<stdio.h> /* または wchar.h */
intvwprintf(constwchar_t*restrictformat,va_listargs);
intvfwprintf(FILE*restrictfp,constwchar_t*restrictformat,va_listargs);
intvswprintf(wchar_t*restrictstr,size_tsize,constwchar_t*restrictformat,va_listargs);

安全性を向上させたもの

[編集 ]

C11のAnnex K Bounds‐checking interfacesで規定された、安全性を向上させた種類が存在する。それぞれ、関数名の末尾に_sを付けた名称となっている。これらの関数は、__STDC_WANT_LIB_EXT1__1に定義した上で対応するヘッダーをインクルードすると宣言される。

#define __STDC_WANT_LIB_EXT1__ 1
#include<stdio.h>
#include<wchar.h>
intprintf_s(constchar*restrictformat,...);
intfprintf_s(FILE*restrictfp,constchar*restrictformat,...);
intsprintf_s(char*restrictstr,rsize_tsize,constchar*restrictformat,...);
intsnprintf_s(char*restrictstr,rsize_tsize,constchar*restrictformat,...);
intvprintf_s(constchar*restrictformat,va_listarg);
intvfprintf_s(FILE*restrictfp,constchar*restrictformat,va_listarg);
intvsprintf_s(char*restrictstr,rsize_tsize,constchar*restrictformat,va_listarg);
intvsnprintf_s(char*restrictstr,rsize_tsize,constchar*restrictformat,va_listarg);
intwprintf_s(constwchar_t*restrictformat,...);
intfwprintf_s(FILE*restrictfp,constwchar_t*restrictformat,...);
intswprintf_s(wchar_t*restrictstr,rsize_tsize,constwchar_t*restrictformat,...);
intsnwprintf_s(wchar_t*restrictstr,rsize_tsize,constwchar_t*restrictformat,...);
intvwprintf_s(constwchar_t*restrictformat,va_listarg);
intvfwprintf_s(FILE*restrictfp,constwchar_t*restrictformat,va_listarg);
intvswprintf_s(wchar_t*restrictstr,rsize_tsize,constwchar_t*restrictformat,va_listarg);
intvsnwprintf_s(wchar_t*restrictstr,rsize_tsize,constwchar_t*restrictformat,va_listarg);

以下のような機能が追加されている。

  • FILE*や文字列の引数(%sに対応する可変長引数部分の引数も含む)に対するNULLポインタチェック
  • 出力先バッファサイズのチェック
  • %n書式の禁止

エラーは実行時に検出され、現在設定されている制約ハンドラー (constraint handler) 関数が呼ばれる。

Windows API

[編集 ]

Microsoft Windows用のWindows APIには、sprintf()snprintf()などによく似た名前の関数として以下のようなAPIが用意されている[5] [6]

// winuser.h
intwsprintfA(LPSTRunnamedParam1,LPCSTRunnamedParam2,...);
intwsprintfW(LPWSTRunnamedParam1,LPCWSTRunnamedParam2,...);
intwvsprintfA(LPSTRunnamedParam1,LPCSTRunnamedParam2,va_listarglist);
intwvsprintfW(LPWSTRunnamedParam1,LPCWSTRunnamedParam2,va_listarglist);
// shlwapi.h
intwnsprintfA(PSTRpszDest,intcchDest,PCSTRpszFmt,...);
intwnsprintfW(PWSTRpszDest,intcchDest,PCWSTRpszFmt,...);
intwvnsprintfA(PSTRpszDest,intcchDest,PCSTRpszFmt,va_listarglist);
intwvnsprintfW(PWSTRpszDest,intcchDest,PCWSTRpszFmt,va_listarglist);

ここで、LPSTRPSTRchar*LPCSTRPCSTRconstchar*LPWSTRPWSTRwchar_t*LPCWSTRPCWSTRconstwchar_t*に相当するtypedef型エイリアスである。Wサフィックスはワイド文字によるUnicode文字セット、AサフィックスはANSIマルチバイト文字セット(MBCS)を意味する。プロジェクトのUnicode対応設定(マクロシンボルUNICODEの定義有無)によって関数の実装がW版またはA版に切り替わるwsprintfマクロやwnsprintfマクロなども用意されている。

いずれもfloatdoubleといった浮動小数点数型の書式化には対応しておらず、C/C++の標準ライブラリ関数とは互換性がない。Cランタイムライブラリ (CRT) に依存せず、Windows環境限定で標準的に使えることがメリットだが、これらの使用は推奨されておらず、<strsafe.h>で定義されているセーフ文字列関数の使用が推奨されている[7]

なお、Windows API関数の呼び出し規約は、ほぼすべて_stdcall(__stdcallWINAPI / STDAPICALLTYPE)であるが、上記のうち可変長引数...を受け取るAPI関数は例外的に_cdecl(__cdeclWINAPIV / STDAPIVCALLTYPE)となっている。x86の場合は引数の受け渡し動作が呼び出し規約に左右される。

コード例

[編集 ]
#include<stdio.h>
intmain(void)
{
inta=1234;
printf("%d %o %x\n",a,a,a);
printf("%s %c\n","abc",'x');
return0;
}

上記のコードをコンパイルし実行すると、次の出力が得られる。

1234 2322 4d2
abc x

脆弱性

[編集 ]
書式文字列攻撃」を参照

一般に、書式文字列を外部や利用者から自由に指定できる状態とすることはセキュリティホールの温床となるため望ましくない。特に%n書式を用いたものが有名である[8] 。Visual C++のCRTでは既定で%n書式が無効化されており、使用できなくなっている[9]

また、書式化文字列中の書式指定子と実引数の数や型が正しく対応していない場合は未定義動作を引き起こす。Cの可変長引数は型消去によって実現される仕組みであるため、printf()の内部では書式と実引数の数や型の不一致を検出することができず、本質的に安全性が欠如している。正しい書式を与えることはプログラマ側の責任である。

なお、引数で受け取ったバッファに書式化された文字列を出力する関数群は、バッファサイズを超えてデータを書き込んでしまうと未定義動作を引き起こす。特に、sprintf()vsprintf()といったバッファサイズ(書き込み可能な最大サイズ)を指定することのできない関数は潜在的なバッファオーバーフローの脆弱性を抱えているため使うべきではなく、代わりにC99で追加されたsnprintf()vsnprintf()を使うべきである。

他言語

[編集 ]

C言語から派生したC++D言語はもとより、PHP [10] Ruby [11] Perlなど他の言語でもprintfが実装されている。Python 2.xではprintだったが、3.xではprint関数となった。

また、Ruby[12] やPythonなど、%演算子によってsprintf()相当機能をサポートするものも存在する。Boost C++ライブラリのBoost.Format[13] では、boost::formatクラスの%演算子オーバーロードによって類似の機能を実現している[14]

C++11ではC99のライブラリ関数の多くが取り込まれた。C++20では関数テンプレートstd::format()[15] が、C++23ではstd::print()[16] が追加された。

Unix系オペレーティングシステムのコマンドとして実装されたprintf (英語版)もある。外部コマンドのほか、Bashなど一部のUnixシェルではビルトインで実装されている。

Java

[編集 ]

Java 1.5ではString クラスにformat()メソッドが、java.io.PrintStream クラスにformat()メソッドとprintf()メソッドが追加された。

標準出力の場合は、例えば以下のように呼び出すことができる。

System.out.printf("Integer = 0x%02X, Double = %.4f\n",10,Math.PI);

Javaの可変長引数はObject の配列だが、intdoubleのようなプリミティブ型の引数はオートボクシング(自動ボックス化)によってプリミティブラッパークラスにラップされて渡されるため、オーバーヘッドはあるものの本質的に型安全である。書式指定に誤りがあった場合はjava.util.IllegalFormatException 例外を、また書式指定に対応する実引数が不足していた場合はjava.util.MissingFormatArgumentException 例外をスローする。

Javaに限らず、後発のオブジェクト指向言語や動的型付け言語の場合は、可変長引数として使われるコレクション(配列やリスト)が長さ情報を持っており、またコレクション中の各オブジェクトが自分自身の型情報を持っているため、printf()相当機能がバッファ安全かつ型安全に実現できるようになっている。

脚注

[編集 ]

注釈

[編集 ]
  1. ^ 実際のローカライズ作業では、gettext等によってメッセージカタログから文字列を得るようにコードを記述する。
  2. ^ 類似の順序指定可能な書式化機能を持つものとして、Windows APIFormatMessage()関数や、Microsoft Foundation ClassAfxFormatString2()関数、.NET FrameworkSystem.String.Format()メソッドなどが挙げられる。
  3. ^ 可変長引数では「既定の実引数拡張」により、float型の引数はdouble型へと変換されるため、本来はdoubleに対して修飾子を適用する必要はない。
  4. ^ 例えばLP64環境ではlong64ビットであり、仮にint64_t型の実引数に対して%ld書式を使用したとしてもほとんどの実装では期待通り動作する可能性が高いが、LLP64環境ではlong32ビットであり、int64_t型の実引数に対して%ld書式を使用すると未定義動作を引き起こす。また、longlongは少なくとも64ビット以上の値を表現できることが保証されているが、int64_tと同じ型であるという保証はどこにもなく、int64_t型の実引数に対して%lld書式を使用した場合の動作はやはり未定義となる。同様に、intint32_tが同じ型であるという保証もない。
  5. ^ Microsoft Visual C++には非標準関数としてバッファサイズを受け取らないswprintfが存在するが、バージョン2005 (8.0) 以降では既定で無効化されており、非推奨となっている[3] [4]

出典

[編集 ]
  1. ^ Fixed width integer types (since C99) - cppreference.com
  2. ^ 固定幅の整数型 (C99以上) - cppreference.com
  3. ^ sprintf、swprintf (CRT) | Microsoft Docs
  4. ^ sprintf, _sprintf_l, swprintf, _swprintf_l, __swprintf_l | Microsoft Docs
  5. ^ wsprintfA function (winuser.h) - Win32 apps | Microsoft Learn
  6. ^ wnsprintfA function (shlwapi.h) - Win32 apps | Microsoft Learn
  7. ^ セーフ文字列関数の使用 - Windows drivers | Microsoft Learn
  8. ^ "第10章 著名な脆弱性対策 フォーマット文字列攻撃対策". IPA ISEC セキュア・プログラミング講座:C/C++言語編. 独立行政法人 情報処理推進機構. 2012年7月3日閲覧。
  9. ^ Format Specification Syntax: `printf` and `wprintf` Functions | Microsoft Learn
  10. ^ "PHP: printf". PHPマニュアル (2013年3月22日). 2013年3月28日閲覧。
  11. ^ "Kernel.#printf". Ruby 1.9.3 リファレンスマニュアル . 2013年3月28日閲覧。
  12. ^ "Instance method String#%". Ruby 1.9.3 リファレンスマニュアル . 2013年3月28日閲覧。
  13. ^ "The Boost Format Library" (2006年12月2日). 2013年3月28日閲覧。
  14. ^ 文字列フォーマット - boostjp
  15. ^ format - cpprefjp C++日本語リファレンス
  16. ^ print - cpprefjp C++日本語リファレンス

参考文献

[編集 ]
  • JIS X 3010:2003 プログラミング言語C
  • N1570 (PDF) (C11の最終ドラフト)

関連項目

[編集 ]

外部リンク

[編集 ]
ウィキブックスにC言語 関連の解説書・教科書があります。

AltStyle によって変換されたページ (->オリジナル) /