2017-01-20 14 views
2

シグナルは、その引数の1つとしてコールバック関数をとります。私は関数内で関数を作成したいと思います。これは今まで私の試みです:C - 高次関数

typedef void (*sighandler_t)(int); 
sighandler_t f(int pid) { 
    void sigintHandler(int sig) { 
     printf("Process %d", pid); 
    } 
    return sigintHandler 
} 

int main(void) { 
    ... 
    if (signal(SIGTSTP, *f(1)) == SIG_ERR) { 
     ... 
    } 
    ... 
} 

しかし、私はSIGTSTP(Ctrl-z)を送信するたびに、私はsegフォールトを取得します。


サイドノートとして:一般的にsegフォルトをデバッグする方法についてのヒントは本当に感謝しています!

+3

標準Cは他の関数の中で関数を定義することをサポートしていないので、これは完全にコンパイラ依存です。なぜあなたは他の内部の関数を定義する必要がありますか?また、[GCCのドキュメント](http://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html)によると、* "包含する関数が終了した後にそのアドレスからネストされた関数を呼び出そうとすると、 * – clcto

+1

'pid'をグローバル変数に入れることはできません(' volatile sig_atomic_t'にする必要があります)。 – HolyBlackCat

+1

ええ、私はグローバル変数を使うことができると思います。私はかなり初心者のCプログラマであり、私は一般的に教えられている[global = bad](http://wiki.c2.com/?GlobalVariablesAreBad) –

答えて

-1

私があなたのセグメンテーション違反を理解するのを助けることができます。

関数を呼び出すと、いくつかのことが行われます。

  1. プッシュ機能の引数は
  2. プッシュリターンアドレスがスタックからスタックから
  3. 関数本体
  4. ポップリターンアドレス機能アドレスへ
  5. ポップ関数の引数を
  6. ジャンプを積層するスタックに。

1,2,6がコールスコープで行われる場合。

シグナルがvoid argumentsであるため、コール(1)は引数を0のスタックにプッシュします。

return(6)は、「除外者」intをスタックからポップして破損させます。あなたはパラメータで信号機能を持つことができません


は何をすることができます

ややソリューションです:

  1. あなたは、信号関数内でグローバル変数を読み込むことができます。プログラムの現在の状態を読み取ることができます。

  2. あなたはprocess_id、thread_idを取得するためにsys_callを実行できます。

  3. あなたのスタックを以前のスコープに読み込んでローカル変数を取得することはできません。 BIGでは、信号を設定する機能ではなく、信号の瞬間に実行していた機能であることに注意してください。

2

あなたのコードは構文的に正確でコンパイル拡張機能を使用しているためコンパイルされます。しかし、あなたのコードには、segfaultにつながるいくつかの根本的な問題があります。

まず、あなたのシグナルハンドラコード:

typedef void (*sighandler_t)(int); 
sighandler_t f(int pid) { 
    void sigintHandler(int sig) { 
     printf("Process %d", pid); 
    } 
    return sigintHandler; 
} 

これはnot standard Cであっても、実際にコンパイルするgccの一部のバージョンで指定することが-ftrampolinesフラグが必要です。あなたのシグナルハンドラ関数がreturn sigintHandler;によってf戻り、あなたが関数ポインタを返すしているとき

sigintHandlerは、このように、nested functionです:

あなたのシグナルハンドラ関数自体を解決する必要があるいくつかの問題があります。あなたのコードで

あなたはtypedef void (*sighandler_t)(int);を持っているので、これはvoid戻り値の型を持つ関数を指すとあなたのsigintHandlerは次のように定義されたパラメータとしてintを取ることができ、関数ポインタ型を定義し、正しくコンパイル。代わりに、あなたのシグナルハンドラ関数は、単にのように書くことができ

:あなたの主な機能で

void sigintHandler(int sig) { 
    printf("Signal %d\n", sig); 
} 

、次のしている:

if (signal(SIGTSTP, *f(1)) == SIG_ERR) { 
    // ....  
} 

ここでは、同様にこのことを指摘しなければならないいくつかを持っています問題。最初に、signal関数は、最初のパラメータとしてシグナル番号(通常はsignal.hヘッダーで定義されたマクロ)をとり、2番目の引数としてvoid func_name(int sig)と定義された関数へのポインタをとります。

これは、です。この関数をポインタとして渡すのではなく、と呼びます。

*f(1)は実際にfを呼び出し、パラメータとして1を渡します。代わりに、あなたは次のように変更になります。

if (signal(SIGTSTP, f) == SIG_ERR) { 
    // ....  
} 

をしかしfはなくvoidの関数ポインタを返すように定義されているので、これは警告/エラーを発する必要があります。

#include <stdio.h> 
#include <signal.h> 

void sigintHandler(int sig) { 
    printf("Signal %d", sig); 
} 

int main(void) { 
    // ... 
    if (signal(SIGTSTP, sigintHandler) == SIG_ERR) { 
     // ... 
    } 
    // ... 
    return 0; 
} 

あなたはしかし、次のように述べています:...

は、変数の挙動を持つために

だから準拠するようにコードを変更するには、あなただけの次の操作を行うことができこれはあなたが意図している変数の性質に依存しますが、信号に基づいて可変関数であれば、次のようなことができます:

#include <stdio.h> 
#include <signal.h> 
#include <unistd.h> 

void sig_stop(int sig) { 
    printf("Process %d stop\n", getpid()); 
} 

void sig_int(int sig) { 
    printf("Process %d interrupt\n", getpid()); 
} 

int main(void) { 
    // ... 
    if (signal(SIGTSTP, sig_stop) == SIG_ERR) { 
     // ... 
    } 
    if (signal(SIGINT, sig_int) == SIG_ERR) { 
     // ... 
    } 
    // ... 
    return 0; 
} 

それともswitchステートメントを使用することができます

一般的にワンセグ障害をデバッグする方法上の任意のヒントが本当にいただければ幸いです!

まず、segmentation faultが何であるかを理解してください。 gdbのようなデバッガを使用してコードをステップ実行するか、クラッシュダンプを調べて具体的にsegfaultが起きている場所を調べることができます。

希望に応じることができます。

関連する問題