#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void eat() // clears stdin upto and including n OR EOF
{
int eat;while ((eat = getchar()) != 'n' && eat != EOF);
}
int main(){
printf("n COMMAND : "); char cmd[21]=""; scanf("%20s",cmd);
if(strcmp(cmd,"shell")==0||strcmp(cmd,"sh")==0)
{
getchar(); // absorb whitespace char separating 'shell' and the command, say 'ls'
while(1)
{
printf("n sh >>> "); // print prompt
char shellcmd[1024]=""; // str to store command
scanf("%1023[^n]",shellcmd); eat(); // take input of command and clear stdin
if(strcmp("close",shellcmd)==0||strcmp("x",shellcmd)==0)
break;
else
system(shellcmd);
}
}
}
在代码中,发生了一些我无法捕捉到的异常行为。
输入sh ls
并按下[ENTER]
后,预期响应为:
- 第一个
scanf()
将sh
存储在cmd[]
中,并将lsn
留在stdin
中 - CCD_ 8占用了CCD_ 9的空间
printf()
将n sh >>>
打印到终端- 第二个
scanf()
将ls
存储在shellcmd[]
中,将n
留在stdin中 eat()
从stdin读取n
,使其为空- 执行
system("ls")
即结果应该是这样的:
COMMAND : sh ls
sh >>>
file1 file 2 file3 ...
sh >>> | (cursor)
但是
我得到的:
COMMAND : sh ls
file1 file2 file3 ...
sh >>>
sh >>> |
显然,第二个scanf()
和shell()
在printf()
之前执行,或者至少这是我的假设。
怎么了?
使用cc -Wall -Wextra -pedantic
在Clang和GCC上编译,并在MacOS和Linux上的bash上测试
您可以在手册页中找到:
如果一个流引用一个终端(就像stdout通常做的那样(,它是行缓冲
因此,每当printf
打印的消息不包含换行符时,您可能会遇到延迟。在另一端,一旦发送了下一个printf
的前导换行符,就会显示上一条消息。
解决方案:
-
在消息
printf("n sh >>> n");
末尾添加一行换行符 -
通过调用
flush()
函数(fflush(stdout)
(,即使没有换行符,也强制显示当前缓冲区 -
使用
setvbuf()
函数更改当前stdout缓冲行为setvbuf(stdout,NULL,_IONBF,0);