कैसे पकड़ता है 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 में संपादित करें : जिनके लिए यह चिंता का विषय हो सकता है, विशेष रूप से इस जवाब को संपादित करने के लिए एक अतुलनीय आग्रह के साथ। देखिए, मैंने यह उत्तर सात साल पहले लिखा था। हां, भाषा के मानक बदल जाते हैं। यदि आपको वास्तव में दुनिया को बेहतर बनाना है, तो कृपया अपना नया उत्तर जोड़ें, लेकिन जैसा मेरा है उसे छोड़ दें। जैसा कि उत्तर में मेरा नाम है, मैं अपने शब्दों को भी शामिल करना पसंद करूंगा। धन्यवाद।
bool volatile keepRunning = true;
100% सुरक्षित होना चाहिए । संकलक keepRunning
एक रजिस्टर में कैश करने के लिए स्वतंत्र है और वाष्पशील इसे रोक देगा। जब लूप कम से कम एक गैर-इनलाइन फ़ंक्शन को कॉल करता है, तो व्यवहार में यह सबसे अधिक संभावना है कि यह अस्थिर कीवर्ड के बिना भी काम कर सकता है।
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 - यह मूल रूप से एक "सुविधा" है, मैं इसे इस तरह से लेता हूं।
यूएन * एक्स प्लेटफार्मों के बारे में परिशिष्ट।
signal(2)
GNU / Linux पर मैन पेज के अनुसार , का व्यवहार signal
उतना पोर्टेबल नहीं है sigaction
:
संकेत का व्यवहार () UNIX संस्करणों में भिन्न होता है, और लिनक्स के विभिन्न संस्करणों में ऐतिहासिक रूप से भिन्न होता है। इसके उपयोग से बचें: इसके बजाय सिगनेशन (2) का उपयोग करें।
सिस्टम V पर, सिस्टम ने सिग्नल के आगे इंस्टेंसेस की डिलीवरी को ब्लॉक नहीं किया और सिग्नल की डिलीवरी हैंडलर को डिफ़ॉल्ट पर रीसेट कर देगी। बीएसडी में शब्दार्थ बदल गया।
इसके 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);
हालांकि आप चाहते हैं कि सिग्नल को संभालें, लेकिन सीमाओं और वॉच के बारे में जानें:
शून्य my_handler (int sig) { / * आपका कोड यहाँ। * / }
@Peter Varo ने डिर्क के उत्तर को अपडेट किया, लेकिन डिर्क ने परिवर्तन को अस्वीकार कर दिया। यहाँ पीटर द्वारा नया उत्तर दिया गया है:
हालांकि उपरोक्त स्निपेट एक सही है 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 ऑपरेटिंग सिस्टम की तुलना में बहुत कम संकेतों को संभालता है; यहाँ देखें । जबकि Win32 में संकेत में SIGINT घोषित है। प्रलेखन में नोट देखें, जो बताता है कि यह वह नहीं करेगा जो आप उम्मीद कर सकते हैं।
#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 के बराबर है, तो प्रिंटफ़ निष्पादित किया गया है।
यह सिर्फ बाहर निकलने से पहले प्रिंट करें।
#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);
}