控制台 I/O:printf 和 scanf 未按预期顺序出现
Console I/O : printf & scanf not occurring in expected order
#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()
在 cmd[]
中存储 sh
并在 stdin
中留下 ls\n
。
getchar()
占了
space.
printf()
打印 \n sh >>>
到终端
- 第二个
scanf()
在 shellcmd[]
中存储 ls
,在标准输入 中留下 \n
eat()
从标准输入中读取 \n
,将其留空
system("ls")
被执行
即结果应该是这样的:
COMMAND : sh ls
sh >>>
file1 file 2 file3 ...
sh >>> | (cursor)
但是
我得到的:
COMMAND : sh ls
file1 file2 file3 ...
sh >>>
sh >>> |
显然,第二个 scanf()
和 shell()
正在执行 before printf()
,或者至少是 my假设。
怎么了?
使用 cc -Wall -Wextra -pedantic
在 Clang 和 GCC 上编译并在 MacOS 上的 bash 和 Linux
上测试
您可以在 man page 中找到:
If a stream refers to a terminal (as stdout normally does) it is line buffered
因此,当 printf
不包含换行符时,您可能会延迟看到打印的消息。在另一端,一旦发送下一个 printf
的前导换行符,就会显示上一个消息。
解决方案:
在您的消息末尾添加换行符printf("\n sh >>> \n");
通过调用 flush()
函数 (fflush(stdout)
)
强制显示当前缓冲区,即使没有换行符
使用setvbuf()
函数
改变当前的stdout缓冲行为
setvbuf(stdout,NULL,_IONBF,0);
#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()
在cmd[]
中存储sh
并在stdin
中留下ls\n
。 getchar()
占了printf()
打印\n sh >>>
到终端- 第二个
scanf()
在shellcmd[]
中存储ls
,在标准输入 中留下 eat()
从标准输入中读取\n
,将其留空system("ls")
被执行
\n
即结果应该是这样的:
COMMAND : sh ls
sh >>>
file1 file 2 file3 ...
sh >>> | (cursor)
但是
我得到的:
COMMAND : sh ls
file1 file2 file3 ...
sh >>>
sh >>> |
显然,第二个 scanf()
和 shell()
正在执行 before printf()
,或者至少是 my假设。
怎么了?
使用 cc -Wall -Wextra -pedantic
在 Clang 和 GCC 上编译并在 MacOS 上的 bash 和 Linux
您可以在 man page 中找到:
If a stream refers to a terminal (as stdout normally does) it is line buffered
因此,当 printf
不包含换行符时,您可能会延迟看到打印的消息。在另一端,一旦发送下一个 printf
的前导换行符,就会显示上一个消息。
解决方案:
在您的消息末尾添加换行符
printf("\n sh >>> \n");
通过调用
强制显示当前缓冲区,即使没有换行符flush()
函数 (fflush(stdout)
)使用
改变当前的stdout缓冲行为setvbuf()
函数setvbuf(stdout,NULL,_IONBF,0);