• ベストアンサー

signal関数の使い方

標準関数のsignal()関数についてですが void (*signal(int sig, void (*func)(int)))(int); 関数の形式からしてよくわかりません。 僕のイメージでは関数のポインタというと void (*func)(int,int) という感じですが上の場合 void (*func(int,int))(int) /*引数は仮にint型*/ という形式になってますよね。末尾の(int)は引数のはずですがどこの引数になっているのかよくわかりません。 しかも関数の使用例などをみると signal(SIGINT, func); という形で使っており末尾の(int)がどこにいったのかさっぱりわかりません。 よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.3

void (*signal)(int sig, void (*func)(int)); では、signalは関数ではなく、関数へのポインタを格納する変数になります。 最初の void (*signal(int sig, void (*func)(int)))(int); を解きほぐしてみましょう。 void (*A)(int); は「intを引数としvoidを返す関数」へのポインタ変数です。 void (*A())(int); は「intを引数としvoidを返す関数」へのポインタを返す関数です。 void (*A(int))(int); は「intを引数とし「intを引数としvoidを返す関数」へのポインタを返す関数」です。 void (*A(int, void(*)()))(int); は「intと「voidを返す関数へのポインタ」を引数とし「intを引数としvoidを返す関数」へのポインタを返す関数」です。 void (*A(int, void(*)(int)))(int); は「intと「intを引数としvoidを返す関数へのポインタ」を引数とし「intを引数としvoidを返す関数」へのポインタを返す関数」です。 void (*A(int sig, void(*func)(int)))(int); は上と同じで、引数に名前をつけただけです。

jimihenn
質問者

お礼

非常に親切なお答え大変ありがとうございました。 やっとわかりました! 特に11行目が感動しました! 何度もお答え頂きお手数かけました。

その他の回答 (3)

回答No.4

#1のかた、#2のかたと重複しますが、わたくしなりに解説させてください。 void (*signal(int sig, void (*func)(int)))(int); というのは、signalという名前の関数のプロトタイプ宣言である、というのは良いですよね。 ではその解釈です。 signal(int sig, void (*func)(int)) の部分を取り出すと、すでにご理解している通り、引数は、 int型のものが第1引数であり、 void (*)(int)型のもの(つまりint型を1つ取り、戻り値なしの関数へのポインタ)が第2引数です。 では、戻り値を見てみましょう...残りの部分を取り出すと解ります。 void (*)(int)型です。 実は、第2引数と同じ型のものを戻り値として戻すんですね。 この一見わかりにくい型は、つぎのように解釈します。(内側から解釈していくのがポイント) 1...*なので、ポインタである。 2...()で囲まれているので、ポインタはポインタだけど、変数ポインタではなくて関数ポインタである。 3...(int)とあるので、その関数はint型を引数に1つだけとる。 4...その関数の戻り値の型はvoid型(つまり戻り値なし)である。 ご理解いただけるとよいのですが... 参考まで。

jimihenn
質問者

お礼

非常に詳しいご回答大変ありがとうございます。 やっと理解できました。 関数ポインタの戻り値の構造を理解できてなかったようでした。

回答No.2

void (*signal(int sig, void (*func)(int)))(int); の最後の(int)は、signalが返すのは関数へのポインタで、その関数が整数引数を一個とるということです。 意味は、 void signalhandler(int x) { ... } があるときに void (*oldhandler)(int); oldhandler = signal(SIGINT, signalhandler); /* ハンドラの設定 */ ... (void)signal(SIGINT, oldhandler); /* 古いハンドラの回復 */ のように使えるという意味です。

jimihenn
質問者

お礼

ありがとうございます。 やっぱりちょっと理解できてません。 この場合関数のポインタは signalとfuncですよね? void (*signal(int sig, void (*func)(int)))(int); ↑これだと signalの引数は「int sig, void (*func)(int)」で、funcの引数は「int」となり、 末尾の「int」がこのプロトタイプからどう解釈すればいいのかわかりません。 もし void (*signal)(int sig, void (*func)(int)); だとすればプロトタイプとしてはわかりますが意味は違ってくるのでしょうか? もしお時間あればよろしくお願いします。

回答No.1

typedef void (*signal_func)(int); signal_func signal(int, signal_func); と書き直せば理解できますか?

jimihenn
質問者

お礼

ありがとうございます。 なんとなく見えてきました。

関連するQ&A

  • 「void ( *signal(int sig, void (*func)(int)) ) (int)」の (int)

    signal関数の書式についてですが、   void ( *signal(int sig, void (*func)(int)) ) (int); 最後に付く(int)は一体何でしょうか? このような関数の書式ははじめて見ました。 UNIX系の何かでしょうか。 回答よろしくお願いします。

  • C言語での関数の引数の受け渡しについて

    C言語での関数の引数の受け渡しについて教えてもらいたいのです。 char *p=Goo;  というポインタpがmain関数で定義され、このポインタpをある関数 void func(・・・) に渡すことは出来ますか? つまりポインタを実引数として扱うことはできるのかという事ですが・・・ int p=10; とかだったら、 void func(int test) の関数には、main関数で func(p) で仮引数testにわたせると思うんですが・・・ もし出来るようでしたら、関数の渡し方と定義の記述を教えてください。 どうか宜しくお願いします。

  • 関数の受け渡し

    C言語の質問です。 WinAPIのDialogBox関数の4番目の引数のように、 関数を別の関数に受け渡すにはどうしたらよいでしょうか。 int Func1() { } void Func2(int Func) { Func() ; } int main() { Func2(Func1) ; } このようなイメージなのですが、なにやらエラーが・・・・・・ 修正をお願いいたします。 ちなみに環境はVistaとBCCです。

  • 関数原型宣言について

    関数原型宣言について 下記のプログラムのfunc関数は、関数原型宣言 <func(int a, long b, char *c);>が述されていないのにfunc関数の仮引数の型longは、関数原型宣言が与えられるといると本に書かれていたのですが、何故でしょうか教えて頂きたい。 ******************************************** #include <stdio.h> /*--- 三つの引数を受け取る関数 ---*/ void func(int a, long b, char *c) { int x; long y; /* … */ } int main(int argc, char *argv[]) { int a = 1; char s[] = "abc"; func(a + 3, 2, s); return (0); } *************************************************************

  • C言語の基本的な質問ですが、関数へのポインタの宣言

    関数へのポインタの質問です。 下のように、関数へのポインタを使ったプログラムを書きました。 (関数へのポインタを理解するためのものなので、実用的な意味はありません。(*^_^*) また、このプログラムはコンパイルもリンクも実行も問題なく出来ます。) #include <stdio.h> int add_func(int,int); (*func_p0) (int,int); int main(void) { int (*func_p1) (int,int); int (*func_p2) ( ); int hoge0,hoge1,hoge2; func_p0=add_func; hoge0=func_p0(3,5); printf("0 : 3+5は%d\n",hoge0); func_p1=add_func; hoge1=func_p1(3,5); printf("1 : 3+5は%d\n",hoge1); func_p2=add_func; hoge2=func_p2(3,5); printf("2 : 3+5は%d\n",hoge2); return(0); } int add_func(int x, int y) { return(x+y); } func_p0のように戻り値の型を書かない場合と、func_p1やfunc_p2のように戻り値の型を書くのとでは何が違うのでしょうか。 func_p0は外部変数ですが、自動変数にする(main関数の中で同様に宣言。)とコンパイルエラーになります。 それはなぜですか。 func_p1のように引数の型が書いてあるのと、func_p2のように引数の型が書いていないのでは何が違うのでしょうか。 int (*func_p2) ( );というのは、int (*func_p2) (void);とは違うんですよね?

  • ラムダ式を関数に渡したいのですが

    Class1からClass2にある関数の引数にラムダ式で関数を渡すようなプログラムを作ろうと思い、以下のようにコードを記述しました。 #include <iostream> class Class1 { int i = 0; void func() { std::cout << "Hello world" << std::endl; } void init() { Class2 *class2 = new Class2(); class2->setFunc([this] { func(); i++; }()); } }; class Class2 { void(*mFunc)(); void runFunc(){ mFunc(); } public: void setFunc(void func()) { mFunc = func; } }; すると class2->setFunc([this] { func(); i++; }()); のところで「型"void"の引数は型"void(*)()"のパラメーターと互換性がありません」というエラーが発生してしまいます。 キャプチャにthisを渡したラムダ式を他のクラスの関数ポインタのような変数に代入させるようにしたいのですがどのように記述したらできますか

  • 教えてポインタ

    例えば、以下のようなソース。 関数の中で、引数のポインタに値を入れてmainに戻す。 とても簡単なものです。 void func(int *N) {  *N=0; } main {  int  *N=1;  func(N);  printf("%d",*N) } 疑問は、ここからです。 (1)void func(int  *N) (2)void func(int*  N) (3)void func(int*  &N) 上記は、何が違いますか? なお、当方のVS2010で同じソースを作ると、 (1)の場合、エラーになります。(func関数の*N=0のところでダウン) (2)だと、OKになります。 (3)は、なに?

  • signalについて

    いつもお世話になります。 基本的なことですが、お教えください。 C言語の本に、「signalによる割り込み処理」というプログラムが載っていました。 本の説明では、「UNIXでは、シグナルといったもので、割り込み処理を行うことができます。」と、UNIXの話をしているようです。 私の環境はWindowsですが、かまわずに作って実行してみました。 そのプログラムは以下のとおりです。 #include <stdio.h> #include <signal.h> #include <stdlib.h> /* この行は自分で加えた */ void onsig(int sig) { printf("Control+C\n"); exit(0); } int main(void) { signal(SIGINT, onsig); while(1) { puts("a"); /* ★このputsは自分で加えた ★ */ } return 0; } 意図したとおりに、コントロール+Cを押すと Control+Cが表示されて終わりました。 さて、私はonsig関数の中の exit(0); を削除してみました。 実行すると、はじめたくさんの a が表示され、 コントロール+Cを押すとControl+Cの表示の後すぐにそのままwhileの中に戻っていき、 たくさんのa が表示されて、 再びコントロール+Cを押すとプログラムが終わってプロンプトが戻ってくることがわかりました。 ここで疑問に思ったのは、1回目のコントロール+C の後にすぐにwhileの中に戻っていくのならば、何回 コントロール+Cを押してもwhileの中に戻っていき、コントロール+Cで終わらせることは出来ないのではないか、ということでした。 なぜ2回目のコントロール+Cで終了するのでしょうか。 VC++6.0でWin32 Console Applicationで作成しています。

  • 関数の引数をvoid*でキャストする

    最近見かけたCのプログラムで、関数の引数の型は void* なのですが、その関数を使うときに 引数をvoid*でキャストしていました。 例えば、 func ( (void*) p ); こういうことです。 私の知っている知識では、 void* と 任意の型のポインタは キャストなしに相互に代入可能です。 関数の引数でも、キャストは要らないものだと思っていました。 そうすると、引数を void* でキャストするのは無意味だと思うのですが、・・・ 違うのでしょうか。処理系によるとか。 逆に、関数の引数の型がchar*などで、渡すものが void* のときはどうなのでしょうか。 下のプログラムは、関数byte_orderの引数の型はvoid*ですが、int型へのポインタ( &a )を設定しています。私の環境では、コンパイルエラーも警告もないし、動作も正常です。 #include <stdio.h> #include <string.h> void byte_order(void *vp) { char char_array[4]; strncpy(char_array, vp, 4); printf("出力します:%x %x %x %x\n", char_array[0], char_array[1], char_array[2], char_array[3]); } int main(void) { int a = 0x12345678; byte_order(&a); return 0; } このプログラムは単なる一例であって、質問はバイトオーダに関するものではありません。 また、C言語の質問であって、C++ではありません。

  • 関数ポインタについて

    関数ポインタを使用する際に、 指定する先の関数でデフォルト引数が指定されている場合、 関数ポインタを用いて、その引数を省略して呼び出すことはできるのでしょうか? 以下例とします。 void function(int a = 10){}; typedef void (*test)(int a); test a = &function; a(); //このように呼び出したい

専門家に質問してみよう