2017-01-20 2 views
2

신호는 인수 중 하나로 콜백 함수를 사용합니다. 가변 동작을하려면 함수 내에서 함수를 만들고 싶습니다. 이것은 지금까지의 시도입니다 :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. sys_call을 통해 process_id, thread_id를 얻을 수 있습니다.

  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하고 심지어 -ftrampolines 플래그가 실제로 컴파일 gcc의 일부 버전에 지정해야합니다. 당신의 신호 핸들러 함수가 return sigintHandler;에 의해 f 반환, 당신은 함수 포인터를 반환 할 때

sigintHandler는 따라서, nested function입니다 :

귀하의 신호 처리기 함수 자체가 해결해야 할 몇 가지 문제가 있습니다. 당신이 void 반환 유형이 함수를 가리 키와 sigintHandler는 다음과 같이 정의 된 매개 변수로서 int을 할 수있는 함수 포인터 유형을 정의 typedef void (*sighandler_t)(int);을 가지고 있기 때문에 코드에서

이 올바르게 컴파일합니다.

대신, 신호 처리기 기능은 단순히 기록 될 수있다 : 당신의 주요 기능에

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

다음과 같습니다

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

는 주목해야한다이뿐만 아니라이 일부 문제. 먼저 signal 함수는 첫 번째 매개 변수로 신호 번호 (일반적으로 signal.h 헤더에 정의 된 매크로)를 취하고 두 번째 인수는 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 문 사용할 수 있습니다 일반적으로 SEG 오류를 디버깅하는 방법에 대한 팁 정말 감사하겠습니다

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

void sigHandler(int sig) { 
    printf("Process %d received %d\n", getpid(), sig); 
    switch (sig) { 
     case SIGTSTP: 
      // do stop code 
      break; 
     case SIGINT: 
      // do interupt code 
      break; 
    } 
} 

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

을!

먼저 segmentation fault이 무엇인지 이해하십시오. gdb과 같은 디버거를 사용하여 코드를 단계별 실행하거나 크래시 덤프를 검사하여 segfault이 어디에서 발생하는지 확인할 수 있습니다.

희망이 도움이 될 수 있습니다.