[c] C에서 Ctrl-C를 잡아라

C에서 어떻게 Ctrl+ C를 잡을 까요?



답변

신호 처리기

다음은에서 bool사용되는 간단한 예제 입니다 main().

#include <signal.h>

static volatile int keepRunning = 1;

void intHandler(int dummy) {
    keepRunning = 0;
}

// ...

int main(void) {

   signal(SIGINT, intHandler);

   while (keepRunning) { 
      // ...

2017 년 6 월 편집 : 특히이 답변을 편집 할 수없는 욕구가있는 사람. 이 대답은 7 년 전에 썼습니다 . 예, 언어 표준이 변경되었습니다. 세상을 더 나아 져야한다면, 새로운 답변을 추가 하되 그대로 내버려 두십시오. 대답에는 내 이름이 있으므로 단어도 포함하는 것이 좋습니다. 감사합니다.


답변

여기를 확인하십시오 :

참고 : 분명히, 이것은 설명하는 간단한 예입니다 단지 셋업하는 방법 CtrlC핸들러를하지만 항상 필요가 뭔가를 파괴하지 않기 위해 순종 할 것을 규칙이 있습니다. 아래의 의견을 읽으십시오.

위의 샘플 코드 :

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

void     INThandler(int);

int  main(void)
{
     signal(SIGINT, INThandler);
     while (1)
          pause();
     return 0;
}

void  INThandler(int sig)
{
     char  c;

     signal(sig, SIG_IGN);
     printf("OUCH, did you hit Ctrl-C?\n"
            "Do you really want to quit? [y/n] ");
     c = getchar();
     if (c == 'y' || c == 'Y')
          exit(0);
     else
          signal(SIGINT, INThandler);
     getchar(); // Get new line character
}


답변

UN * X 플랫폼에 관한 부록.

signal(2)GNU / Linux 의 매뉴얼 페이지에 따르면 , signal동작은 sigaction다음 과 같이 이식성이 없습니다 .

signal ()의 동작은 UNIX 버전에 따라 다르며 역사적으로 Linux 버전에 따라 다릅니다. 사용을 피하십시오 : 대신 sigaction (2)를 사용하십시오.

System V에서 시스템은 신호의 추가 인스턴스 전달을 차단하지 않았으며 신호 전달은 핸들러를 기본 인스턴스로 재설정합니다. BSD에서 의미가 변경되었습니다.

Dirk Eddelbuettel의 이전 답변에 대한 다음 변형은 다음 sigaction대신 사용 합니다 signal.

#include <signal.h>
#include <stdlib.h>

static bool keepRunning = true;

void intHandler(int) {
    keepRunning = false;
}

int main(int argc, char *argv[]) {
    struct sigaction act;
    act.sa_handler = intHandler;
    sigaction(SIGINT, &act, NULL);

    while (keepRunning) {
        // main loop
    }
}


답변

또는 다음과 같이 터미널을 원시 모드로 설정할 수 있습니다.

struct termios term;

term.c_iflag |= IGNBRK;
term.c_iflag &= ~(INLCR | ICRNL | IXON | IXOFF);
term.c_lflag &= ~(ICANON | ECHO | ECHOK | ECHOE | ECHONL | ISIG | IEXTEN);
term.c_cc[VMIN] = 1;
term.c_cc[VTIME] = 0;
tcsetattr(fileno(stdin), TCSANOW, &term);

이제를 사용하여 Ctrl+ C키 입력 을 읽을 수 있습니다 fgetc(stdin). 더 이상 일반적으로 Ctrl+ Z, Ctrl+ Q, Ctrl+ S등 을 사용할 수 없으므로 이것을 사용하십시오 .


답변

트랩을 설정하십시오 (한 핸들러로 여러 신호를 트랩 할 수 있음).

신호 (SIGQUIT, my_handler);
신호 (SIGINT, my_handler);

원하는대로 신호를 처리하되 제한 사항과 문제점에 유의하십시오.

void my_handler (int sig)
{
  / * 여기 코드가 있습니다. * /
}


답변

@Peter Varo는 Dirk의 답변을 업데이트했지만 Dirk는 변경을 거부했습니다. Peter의 새로운 답변은 다음과 같습니다.

위의 코드 조각은 맞지만 예를 들어, 가능한 경우 이후 표준에서 제공하는보다 현대적인 유형과 보증을 사용해야합니다. 따라서 여기를 찾고있는 사람들을위한 더 안전하고 현대적인 대안이 있습니다. 적합한 구현 :

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

static volatile sig_atomic_t keep_running = 1;

static void sig_handler(int _)
{
    (void)_;
    keep_running = 0;
}

int main(void)
{
    signal(SIGINT, sig_handler);

    while (keep_running)
        puts("Still running...");

    puts("Stopped by signal `SIGINT'");
    return EXIT_SUCCESS;
}

C11 표준 : 7.14§2 헤더 는 비동기 인터럽트가있는 경우에도 원자 엔티티로 액세스 할 수있는 객체의 (휘발성으로 한정된) 정수 유형 인 유형을 <signal.h>선언합니다 sig_atomic_t.

더욱이:

C11 표준 : 7.14.1.1§5abort 또는 raise함수 호출의 결과가 아닌 다른 신호가 발생하는 경우 신호 처리기 static가 잠금없는 원자 객체가 아닌 다른 객체 또는 스레드 저장 기간을 참조하는 경우 동작이 정의되지 않습니다. 로 선언 된 객체에 값을 할당하는 것보다 volatile sig_atomic_t


답변

기존 답변과 관련하여 신호 처리는 플랫폼에 따라 다릅니다. 예를 들어 Win32는 POSIX 운영 체제보다 훨씬 적은 신호를 처리합니다. 여기를 참조하십시오 . SIGINT가 Win32의 signals.h에 선언되어 있지만 설명서의 참고 사항을 참조하십시오.