機能・用法
dup(), dup2(), dup3()はファイルディスクリプタを複製します。
C言語では標準入力, 標準出力, 標準エラー出力がそれぞれファイルディスクリプタが0, 1, 2のデバイスに対応づけられていますが、例えばopen()で開いだファイルのディスクリプタを切り替えたいときなどにこの関数を使います。
使い方
書式
関数の書式は以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 |
#include <unistd.h> int dup(int oldfd); int dup2(int oldfd, int newfd); #define _GNU_SOURCE /* feature_test_macros(7) 参照 */ #include <fcntl.h> /* 定数 O_* の定義の取得 */ #include <unistd.h> int dup3(int oldfd, int newfd, int flags); |
説明・違い
dup()は引数として受け取ったファイルディスクリプタoldfdのコピーを作成したのち、使われていない最も小さい番号のファイルディスクリプタを新しいディスクリプタとして使用します。
一方でdup2()では使われていない最も小さい番号のファイルディスクリプタを使う代わりに引数のnewfdで指定されたディスクリプタが指す番号を使用します。
newfdがすでに使われている場合にはそのディスクリプタをクローズしてから再利用します。
dup2()のいいところは「newfdをクローズして再利用する」という一連の処理がアトミック(これ以上分割できない=競合状態になり得ない)に行われることです。
もしこの処理をdup()とclose()で再現しようとすると、この2つの処理の間に「シグナルハンドラ」や「並列に動作している別スレッド」によってファイルディスクリプタが割り当てられ、newfdについての競合状態に陥る可能性が生じてしまいます。
こういうときにdup2()を使えばアトミックに処理をしてくれるので、newfdをクローズして再利用するまではnewfdをシグナルハンドラや別のスレッドに割り当てられる可能性がありません。
dup3()は基本的にはdup2()と同じですが、flagsにO_CLOEXECを指定することで、新しいファイルディスクリプターに対してclose-on-execフラグを強制的に設定できます。
またoldfdがnewfdと同じ場合にはEINVAL(oldfdとnewfdが同じだったということを意味する)エラーで失敗します。
返り値
dup(), dup2(), dup3()は実行が成功すると新しいファイルディスクリプタを返します。またエラーが起きた場合にはerrnoを適切に設定して返り値として−1を返します。