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 년 전에 썼습니다 . 예, 언어 표준이 변경되었습니다. 세상을 더 나아 져야한다면, 새로운 답변을 추가 하되 그대로 내버려 두십시오. 대답에는 내 이름이 있으므로 단어도 포함하는 것이 좋습니다. 감사합니다.
bool volatile keepRunning = true;
100 % 안전 해야합니다 . 컴파일러는 keepRunning
레지스터에 자유롭게 캐시 할 수 있으며 휘발성으로 인해이를 방지 할 수 있습니다. 실제로 while 루프가 하나 이상의 비 인라인 함수를 호출 할 때 volatile 키워드없이 작동 할 수도 있습니다.
sig_atomic_t
하거나 입력하십시오 atomic_bool
. 방금 그거보고 싶었어 이제 우리가 이야기하고 있기 때문에 : 최신 편집을 롤백하겠습니까? 거기에서 어려운 감정은 당신의 관점에서 완벽하게 이해할 수 있습니다 :)
여기를 확인하십시오 :
참고 : 분명히, 이것은 설명하는 간단한 예입니다 단지 셋업하는 방법 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
}
int main
는 올바른 일이지만 gcc
다른 컴파일러는 이것을 1990 년대부터 올바르게 실행되는 프로그램으로 컴파일합니다. 여기에 꽤 잘 설명되어 있습니다 : eskimo.com/~scs/readings/voidmain.960823.html- 기본적으로 "기능"입니다.
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등 을 사용할 수 없으므로 이것을 사용하십시오 .
@Peter Varo는 Dirk의 답변을 업데이트했지만 Dirk는 변경을 거부했습니다. Peter의 새로운 답변은 다음과 같습니다.
위의 코드 조각은 맞지만 c89예를 들어, 가능한 경우 이후 표준에서 제공하는보다 현대적인 유형과 보증을 사용해야합니다. 따라서 여기를 찾고있는 사람들을위한 더 안전하고 현대적인 대안이 있습니다.c99 과 c11 적합한 구현 :
#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§5
abort
또는raise
함수 호출의 결과가 아닌 다른 신호가 발생하는 경우 신호 처리기static
가 잠금없는 원자 객체가 아닌 다른 객체 또는 스레드 저장 기간을 참조하는 경우 동작이 정의되지 않습니다. 로 선언 된 객체에 값을 할당하는 것보다volatile sig_atomic_t
...
(void)_;
... 그 목적은 무엇입니까? 컴파일러가 사용하지 않는 변수에 대해 경고하지 않습니까?
기존 답변과 관련하여 신호 처리는 플랫폼에 따라 다릅니다. 예를 들어 Win32는 POSIX 운영 체제보다 훨씬 적은 신호를 처리합니다. 여기를 참조하십시오 . SIGINT가 Win32의 signals.h에 선언되어 있지만 설명서의 참고 사항을 참조하십시오.
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
void sig_handler(int signo)
{
if (signo == SIGINT)
printf("received SIGINT\n");
}
int main(void)
{
if (signal(SIGINT, sig_handler) == SIG_ERR)
printf("\ncan't catch SIGINT\n");
// A long long wait so that we can easily issue a signal to this process
while(1)
sleep(1);
return 0;
}
sig_handler 함수는 전달 된 인수의 값이 SIGINT와 같은지 확인한 다음 printf가 실행됩니다.
종료하기 전에 인쇄합니다.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void sigint_handler(int);
int main(void)
{
signal(SIGINT, sigint_handler);
while (1){
pause();
}
return 0;
}
void sigint_handler(int sig)
{
/*do something*/
printf("killing process %d\n",getpid());
exit(0);
}