typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t sighandler);
signal() はシグナル signum の処理方法を handler に設定する。 handler には、 SIG_IGN、 SIG_DFL、 プログラマが定義した関数 (「シグナル・ハンドラ」) のアドレスの いずれかを指定する。
シグナル signum がプロセスに配送されると、以下のいずれかが発生する。
シグナル SIGKILL と SIGSTOP は捕捉できず、無視することもできない。
POSIX によると、 kill(2) や raise(3) で生成できない SIGFPE, SIGILL, SIGSEGV シグナルを無視した後の動作は未定義である。 0 による整数割り算の結果は未定義となる。 ある種のアーキテクチャでは、これは SIGFPE シグナルを生成する。 (同様に負の最大整数を -1 で割ると SIGFPE が生成されるかもしれない。) このシグナルを無視すると無限ループに陥るかもしれない。
SIGCHLD の動作として SIG_IGN を設定した場合の詳細な動作については、 sigaction(2) を参照すること。
シグナル・ハンドラ内から安全に呼び出すことができる、 async-signal-safe functions (非同期シングルで安全な関数) の リストについては signal(7) を参照。
sighandler_t の使用は GNU 拡張である。 各種バージョンの libc でこの型は定義済みである; libc4 と libc5 では SignalHandler を定義している。 glibc では sig_t を定義しており、 _GNU_SOURCE が定義されている場合には sighandler_t も定義されている。 このような型を使用しないと、 signal() の宣言は読みにくいものとなる。
void ( *signal(int signum, void (*handler)(int)) ) (int);
POSIX.1 は、 sigaction(2) を規定することで移植性に関する混乱を解決した。 sigaction(2) はシグナル・ハンドラが起動される際の挙動を明示的に制御できる。 signal() の代わりにこのインターフェイスを使うこと。
オリジナルの Unix システムでは、 signal() を使って設定されたハンドラがシグナルの配送により起動されると、 そのシグナルの処理方法は SIG_DFL にリセットされ、システムは同じシグナルがさらに生成されても シグナルの配送をブロックしなかった。 System V でも、 signal() に対してこれらの挙動を規定している。 こうした挙動はまずく、ハンドラがハンドラ自身を再設定する機会が 来るより前に、同じシグナルがまた配送される可能性がある。 さらに、同じシグナルが立て続けに配送されると、同じシグナルが ハンドラを繰り返し起動されることになる。
BSD では、シグナル処理の挙動を変更することで、この状況を改善した (しかし、残念なことに、 signal() を使ってハンドラを設定する際に挙動が黙って変更される)。 BSD では、シグナルハンドラが起動された際、 シグナルの処理方法はリセットされず、 ハンドラの実行中は、同じシグナルのさらなる生成は配送がブロックされる。
Linux での状況は以下の通りである。
glibc 2 以降では、機能検査マクロ _BSD_SOURCE が定義されていなければ、 signal() は System V 方式となる。 (gcc(1) が標準指定モード (-std=xxx or -ansi) で起動された場合、もしくは _POSIX_SOURCE, _XOPEN_SOURCE, _SVID_SOURCE といった他の様々な機能検査マクロが定義された場合、 デフォルトの _BSD_SOURCE の暗黙の定義は行われない。 feature_test_macros(7) を参照のこと。)