Printf

**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`型）の戻り値を持ち、出力に成功した場合には転送したバイト数、出力に失敗した場合には負数を返却する。

## 形式

```c
#include <stdio.h>
int printf(const char * restrict format, ...);
```


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

### 変換指定
変換指定は次の形式をとる。（[ ]内は省略可能）
 %[引数順][フラグ][最小フィールド幅][.精度][長さ修飾子]変換指定子

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

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

```c
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.
と表示される。これだけならば大きな意味はないが、例えばメッセージを翻訳（ローカライズ）する際、

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

というように書式文字列だけをローカライズすることで、可変長引数の指定順を変更せずに、
 20行目のコマンド hoge は不正です。
という自然な語順の出力を得ることができる。

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

### 長さ修飾子

Cの可変長引数には「既定の実引数拡張」(default argument promotion) と呼ばれる暗黙の型変換が適用される。整数型の場合は汎整数拡張と同じであり、順位 (rank) がよりも低い、、およびの値はに変換される。については、型の値をすべてで表現できる環境の場合はに、そうでない場合はに変換される。の値はに変換される。そのため、`h`、`hh`およびに対する`l`は、printfでは省略可能である。もともとに対する`l`は必要なかったが、あまりに多くのプログラマが間違いを犯し続けたため、標準規格において追認されたという歴史的な経緯がある。ただし、scanfでは実引数としてポインタが渡されるため、長さ修飾子の指定による区別が必要となる。

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

### 変換指定子

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

```c
#include <stdio.h>
int fprintf(FILE * restrict fp, const char * restrict format, ...);
```


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

```c
#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
wprintf, fwprintf, swprintfは、それぞれprintf, fprintf, snprintfに対応し、ワイド文字を使用するものである。C95で標準化された。sprintfに直接対応するワイド文字バージョンの関数（出力バッファサイズを受け取らない関数）は存在しない。

```c
#include <stdio.h> /* または wchar.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, ...);
```


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

```c
#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);
```



```c
#include <stdio.h> /* または wchar.h */
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`に定義した上で対応するヘッダーをインクルードすると宣言される。

```c
#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`書式の禁止

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

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

```c
// winuser.h
int wsprintfA(LPSTR unnamedParam1, LPCSTR unnamedParam2, ...);
int wsprintfW(LPWSTR unnamedParam1, LPCWSTR unnamedParam2, ...);
int wvsprintfA(LPSTR unnamedParam1, LPCSTR unnamedParam2, va_list arglist);
int wvsprintfW(LPWSTR unnamedParam1, LPCWSTR unnamedParam2, va_list arglist);
// shlwapi.h
int wnsprintfA(PSTR pszDest, int cchDest, PCSTR pszFmt, ...);
int wnsprintfW(PWSTR pszDest, int cchDest, PCWSTR pszFmt, ...);
int wvnsprintfA(PSTR pszDest, int cchDest, PCSTR pszFmt, va_list arglist);
int wvnsprintfW(PWSTR pszDest, int cchDest, PCWSTR pszFmt, va_list arglist);
```


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

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

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

## コード例

```c
#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`書式を用いたものが有名である。Visual C++のCRTでは既定で`%n`書式が無効化されており、使用できなくなっている。

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

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

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

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

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

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

### Java
Java 1.5ではクラスにメソッドが、クラスに`format()`メソッドと`printf()`メソッドが追加された。

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

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


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

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

## 脚注
### 注釈

### 出典

## 参考文献
*JIS X 3010:2003 プログラミング言語C
*（C11の最終ドラフト）

## 関連項目
*C言語
*入出力
*Hello world
*scanf
*書式文字列攻撃

## 外部リンク

* UNIX コマンド
** printf(1): format/print data - Linux man page 
** Man page of GNU printf(1) | JM Project 
** [printf(1) | FreeBSD Manual Pages](https://man.freebsd.org/cgi/man.cgi?query=printf(1)) 
** printf(1) man page (Solaris 10 Reference Manual) 
** printf(1) man page（HP-UX リファレンス）
** printf - write formatted output The Open Group Base Specifications Issue 7, 2018 edition
** Bashビルトイン: Bash Builtins (Bash Reference Manual)
* 標準 C ライブラリ
** printf, fprintf, sprintf, snprintf, printf_s, fprintf_s, sprintf_s, snprintf_s - cppreference.com 
** printf, fprintf, sprintf, snprintf, printf_s, fprintf_s, sprintf_s, snprintf_s - cppreference.com 
** printf, _printf_l, wprintf, _wprintf_l | Microsoft Learn 
** printf(3): formatted output conversion - Linux man page 
** Man page of printf(3) | JM Project 
** [printf(3) | FreeBSD Manual Pages](https://man.freebsd.org/cgi/man.cgi?query=printf(3)) 
** printf(3C) man page (Solaris 10 Reference Manual)
** printf(3S) man page（HP-UX リファレンス）