C'de Ctrl+ nasıl yakalanır C?
C'de Ctrl+ nasıl yakalanır C?
Yanıtlar:
Bir sinyal işleyici ile.
İşte saygısız basit bir örnek bool
olarak kullanılan main()
:
#include <signal.h>
static volatile int keepRunning = 1;
void intHandler(int dummy) {
keepRunning = 0;
}
// ...
int main(void) {
signal(SIGINT, intHandler);
while (keepRunning) {
// ...
Haziran 2017'de düzenleyin: Özellikle bu yanıtı düzenleme konusunda doyumsuz bir dürtüye sahip olanlar için endişe duyabilecekleri. Bak, bu cevabı yedi yıl önce yazdım . Evet, dil standartları değişiyor. Dünyayı gerçekten daha iyi hale getirmeniz gerekiyorsa, lütfen yeni cevabınızı ekleyin , ancak benimki olduğu gibi bırakın. Cevabın üzerinde benim adım olduğu için, sözlerimi de içermesini tercih ederim. Teşekkür ederim.
bool volatile keepRunning = true;
% 100 güvenli olmalıdır. Derleyici keepRunning
bir kayıtta önbelleğe almakta serbesttir ve uçucu bunu önleyecektir. Uygulamada, while döngüsü en az bir satır içi olmayan işlevi çağırdığında, büyük olasılıkla değişken anahtar kelime olmadan da çalışabilir.
sig_atomic_t
da atomic_bool
türleri kullanırım . Sadece özledim. Şimdi konuştuğumuzdan beri: son düzenlememi geri almamı ister misiniz? Zor duygular yok, bakış açınızdan mükemmel bir şekilde anlaşılabilir :)
Burayı kontrol et:
Not: Açıkçası, bu sadece bir CtrlCişleyicinin nasıl kurulacağını açıklayan basit bir örnektir , ancak her zaman olduğu gibi başka bir şeyi kırmamak için uyulması gereken kurallar vardır. Lütfen aşağıdaki yorumları okuyun.
Yukarıdaki örnek kod:
#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
uygun bir şeydir, ancak gcc
diğer derleyiciler bunu 1990'lardan beri doğru çalışan programlara derler. Burada oldukça iyi açıklanmıştır: eskimo.com/~scs/readings/voidmain.960823.html - temelde bir "özellik", bunu böyle alıyorum.
UN * X platformlarına ilişkin Zeyilname.
signal(2)
GNU / Linux'taki man sayfasına göre , davranışı aşağıdakilerin davranışı signal
kadar taşınabilir değildir sigaction
:
Signal () davranışı UNIX sürümleri arasında değişiklik gösterir ve aynı zamanda tarihsel olarak farklı Linux sürümleri arasında da değişiklik gösterir. Kullanımından kaçının: bunun yerine sigaction (2) kullanın.
Sistem V'de, sistem sinyalin başka örneklerinin verilmesini engellemedi ve bir sinyalin verilmesi işleyiciyi varsayılana sıfırlar. BSD'de anlambilim değişti.
Dirk Eddelbuettel'in önceki cevabının aşağıdaki varyasyonu sigaction
yerine şunları kullanıyor 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
}
}
Veya terminali şu şekilde ham moda koyabilirsiniz:
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);
Şimdi Ctrl+ Ctuş vuruşlarını kullanarak okumak mümkün olmalıdır fgetc(stdin)
. Normalde artık Ctrl+ Z, Ctrl+ Q, Ctrl+ Svb.
Bir tuzak kurun (bir işleyici ile birden fazla sinyal yakalayabilirsiniz):
sinyali (SIGQUIT, my_handler); sinyali (SIGINT, my_handler);
Sinyali istediğiniz gibi kullanın, ancak sınırlamalara ve sorunlara dikkat edin:
void my_handler (int sig) { / * Kodunuz buraya. * / }
@Peter Varo Dirk'ün cevabını güncelledi, ancak Dirk değişikliği reddetti. İşte Peter'ın yeni cevabı:
Yukarıdaki pasaj doğru olmasına rağmen C89örneğin, mümkünse daha sonraki standartlar tarafından sağlanan daha modern tipler ve garantiler kullanılmalıdır. Bu nedenle, iş arayanlar için daha güvenli ve modern bir alternatif.c99 ve c11 uygun uygulama:
#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 Standart: 7.14§2 başlık
<signal.h>
tipi ... ilansig_atomic_t
asenkron kesme mevcudiyetinde, bir atom bir varlık olarak erişilebilir bir nesnenin (muhtemelen uçucu nitelikli) tamsayı türüdür.
Ayrıca:
C11 Standardı: 7.14.1.1§5 Sinyal,
abort
veyaraise
fonksiyonunun çağrılmasından başka bir şey ortaya çıkarsa, sinyal işleyicistatic
kilitsiz atomik nesne olmayan herhangi bir nesneye veya iş parçacığı saklama süresine atıfta bulunursa, davranış tanımsızdır. olarak bildirilen bir nesneye bir değer atayarakvolatile sig_atomic_t
...
(void)_;
... Amacı ne? Derleyici kullanılmayan bir değişken hakkında uyarmaz mı?
Mevcut cevaplarla ilgili olarak, sinyal işlemenin platforma bağlı olduğunu unutmayın. Örneğin Win32, POSIX işletim sistemlerinden çok daha az sinyal işliyor; buraya bakın . SIGINT Win32 üzerinde signal.h başlık dosyasında bildirilmiş olsa da, belgelerde beklediğiniz şeyi yapmayacağını açıklayan nota bakın.
#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 işlevi, iletilen bağımsız değişkenin değerinin SIGINT değerine eşit olup olmadığını denetler, ardından printf yürütülür.
Bu sadece çıkıştan önce yazdırın.
#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);
}