Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
2.9k views
in Technique[技术] by (71.8m points)

escaping - How ctrl-d, ctrl-c is handled by C/scanf

Let's take the following program:

# include<stdio.h>
int main(void)
{
    int status, current_number, sum=0;
    printf("Enter a number: ");
    while(status=scanf("%d", &current_number)) {
        sum += current_number;
        printf("Status: %d. The current sum is: %d. Enter another number: ", status, sum);
    }   
}

Enter a number: 2
Status: 1. The current sum is: 2. Enter another number: 3
Status: 1. The current sum is: 5. Enter another number: Status: -1. The current sum is: 8. Enter another number: ^C

It seems that CtrlD (EOF) is recognized as -1 but CtrlC jus causes the program to quit. How are these two escape sequences usually handled in C? And why does scanf treat ctrl-c and ctrl-d differently?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The scanf function does not treat these character in any special way, it doesn't even see those characters. What happens is that the terminal driver (at least under UNIX-like systems(a)) intercepts these keystrokes and translates them to special actions.

For CTRL-d, it closes the standard input file so that any code reading it will get an EOF - that's the -1 you're seeing (indicating an error of some description on read).

For CTRL-c, it raises the SIGINT signal which, if uncaught, will terminate your program.

Keep in mind these are the default key-bindings for those actions, they can be changed with stty to use different ones. The default ones (intr and eof) are shown below (^C and ^D):

pax> stty -a
speed 38400 baud; rows 37; columns 145; line = 0;
intr = ^C; quit = ^; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z;
rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho -extproc

And keep in mind this is probably not what you want:

while(status=scanf("%d", &current_number)) {

The loop will only exit when scanf returns zero, which will happen if an integer cannot be scanned (such as by entering the non-numeric XYZZY). It will continue for any non-zero value, including the -1 you get back on error/end-of-file.

A better loop would be:

while((status = scanf("%d", &current_number)) == 1) {

In fact, since the loop should only ever run for a status value of 1, it makes little sense to use it (other for a final decision on what happened). I'd prefer something like:

#include<stdio.h>
int main(void) {
    int stat, curr, sum = 0;
    printf("Enter a number: ");
    while ((stat = scanf("%d", &curr)) == 1) {
        sum += curr;
        printf("Entered %d, sum is %d, enter another number: ", curr, sum);
    }
    if (stat == -1) {
        prinf("
End of file or I/O error.
");
    } else {
        prinf("Non-numeric data.
");
    }
}

(a) Windows, from memory and by contrast, only recognises CTRL-z at the start of a line (and followed by ENTER) as the end-of-file indicator.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...