Где останавливается выполнение, если в качестве ввода задано прерывание клавиатуры? - PullRequest
4 голосов
/ 05 ноября 2019

У меня есть этот простой кусок кода в файле с именем printftest.c.

#include <stdio.h>

int main(){
    int c, i;

    i = 0;

    while ((c = getchar())  != EOF)
        ++i;

    printf("c = %d\n", c);
    printf("i = %d\n", i);
}

Компиляция и выполнение выполняется следующим образом (в Windows): gcc printftest.c && a.exe

Сеанс терминалавыглядит так:

gcc printftest.c && a.exe
c = -1
^C

Теперь, когда я передаю ctrl-c (прерывание клавиатуры) в качестве ввода в терминале, выполняется только первый оператор printf. Почему это происходит? Я ожидал бы напечатать оба заявления или ни одного. Кто-нибудь может объяснить, где исполнение останавливается и почему?

1 Ответ

3 голосов
/ 05 ноября 2019

Обратите внимание, вот как это работает в Linux. В Windows есть нечто подобное. Это не совсем то же самое, но основной принцип довольно похож. Подробнее о том, как это обрабатывается в Windows, читайте здесь: https://docs.microsoft.com/en-us/windows/console/setconsolectrlhandler

Когда вы вызываете CC, ядро ​​отправит SIGINT программе. Если этот сигнал не обработан программой, он будет уничтожен.

Это делается асинхронно. По сути, это выглядит так:

1) User: C-C
2) Kernel: Hey program, do you hear me? I will kill you if you don't answer.
3) Kernel: The program does not seem to hear me. Let's kill it. 

То, что происходит между 2 и 3, немного азартно. SIGINT обычно используется, чтобы сказать программе, что пользователь устал ждать от того, что делает программа. Ядро принудительно уничтожит программу только в том случае, если оно не обрабатывает SIGINT, но у него нет требований к ее обработке.

Если вы хотите, чтобы поведение было четко определено, вам нужно установить обработчик. Вот пример того, как вы можете изменить свою программу (в Linux), чтобы полностью игнорировать CC:

#include <signal.h>

void install_handler()
{
        static struct sigaction sigact = { 0 };
        sigact.sa_handler = SIG_IGN;
        sigaction(SIGINT, &sigact, NULL);
}

int main()
{
        install_handler()

        // Your code
...