使用CTRL+;基于Linux的Windows子系统开发
我正在使用Windows Linux子系统完成一项作业。下面是用于为此任务编写迷你shell的C代码。 我在使用WSL时遇到了一个有趣的问题。在第35行,您可以看到我调用read函数来读取缓冲区中的内容,它会检查null。在使用WSL的同时按下Ctrl+D,它将进入if语句并无限次地打印第36行上的打印消息,直到我使用Ctrl+C退出时才会停止。当在Linux机器上运行此程序时,它会正常运行并打印一次,并将我们带到循环的顶端。使用CTRL+;基于Linux的Windows子系统开发,c,windows,windows-subsystem-for-linux,C,Windows,Windows Subsystem For Linux,我正在使用Windows Linux子系统完成一项作业。下面是用于为此任务编写迷你shell的C代码。 我在使用WSL时遇到了一个有趣的问题。在第35行,您可以看到我调用read函数来读取缓冲区中的内容,它会检查null。在使用WSL的同时按下Ctrl+D,它将进入if语句并无限次地打印第36行上的打印消息,直到我使用Ctrl+C退出时才会停止。当在Linux机器上运行此程序时,它会正常运行并打印一次,并将我们带到循环的顶端。 你知道这个bug是什么吗 #include <stdio.h&
你知道这个bug是什么吗
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
#include <sys/types
#include <unistd.h>
#include <error.h>
char prompt[] = "$ ";
static int
Fork()
{
pid_t pid;
if ((pid = fork()) < 0)
error(EXIT_FAILURE, errno, "fork error");
return(pid);
}
int
main(void)
{
long MAX = sysconf(_SC_LINE_MAX);
char buf[MAX];
pid_t pid;
int status, n;
do {
write(STDOUT_FILENO, prompt, strlen(prompt));
fflush(NULL);
memset(buf, 0, MAX);
if((n = read(STDIN_FILENO, buf, MAX)) == 0) {
printf("use exit to exit shell\n");
continue;
}
buf[strlen(buf) - 1] = '\0'; // chomp '\n'
if (strncmp(buf, "exit", MAX) == 0) { // match
break;
}
pid = Fork();
if (pid == 0) { // child
execlp(buf, buf, (char *)NULL);
error(EXIT_FAILURE, errno, "exec failure");
}
// parent
if ((pid = waitpid(pid, &status, 0)) < 0)
error(EXIT_FAILURE, errno, "waitpid error");
} while(1);
exit(EXIT_SUCCESS);
}
#包括
#包括
#包括
#包括
#包括
#包括
#include不同的操作系统对EOF使用不同的击键。不同的操作系统对EOF使用不同的击键。关于read()的文档(Linux manpages v 3.54)没有指定文件结尾(ctrl/D)导致read返回除0以外的任何内容。相反,它说返回值零表示文件结束。所以你依赖于未定义的行为。
Linux上的ctrl/D会导致错误,因此read()返回-1。在本例中,您的程序退出循环。或者,按字面读取ctrl/D,然后read()返回1。关于read()的文档(Linux手册页V3.54)没有指定文件结尾(ctrl/D)导致read返回除0以外的任何内容。相反,它说返回值零表示文件结束。所以你依赖于未定义的行为。
Linux上的ctrl/D会导致错误,因此read()返回-1。在本例中,您的程序退出循环。或者,按字面顺序读取ctrl/D,然后read()返回1。您的程序尝试读取文件的末尾。我觉得那不是个好主意。显然,Windows同意了这一点,只是继续在以下读取时返回文件结尾。OT:about:buf[strlen(buf)-1]='\0';//chomp'\n'
这不是删除尾随换行符的可靠方法。更好的方法是:buf[strcspn(buf,“\n”)]='\0'
OT:about:static int Fork(){`将函数命名为相同的a C库函数是一种非常糟糕的编程实践(即使大小写不完全相同)。这可能会让读者感到非常困惑您可能期望的read()被ctrl/D打断,返回-1而不是0。这似乎是依赖于系统的行为。我有一个真正的Ubuntu,它也返回0。即使read()会返回-1,下面的代码也是可疑的。如果strlen(buf)==0会怎么样?那么buf[strlen(buf)-1]
会怎么样?@eryksun我给你的标准规范链接说“如果设置了ICANON,则在处理时应丢弃EOF字符。”。如果WSL未能做到这一点,则必须使用TCIFLUSH
手动丢弃EOF字符。使用TCSET*
来回更改tty模式也可能会产生副作用。但这两种情况都不是必需的(在任何Unix系统上都不是这样)。您的程序尝试读取超过文件结尾的内容。我觉得这不是一个好主意。显然,Windows同意并一直在以下读取中返回文件结尾。OT:about:buf[strlen(buf)-1]='\0';//chomp'\n'
这不是删除尾随换行符的可靠方法。更好的方法是:buf[strcspn(buf,“\n”)]='\0';
OT:about:static int Fork(){`将函数命名为相同的a C库函数是一种非常糟糕的编程实践(即使大小写不完全相同)这可能会让读者非常困惑。你可能希望被ctrl/D中断的read()返回-1而不是0。这似乎是系统相关行为。我有一个真正的Ubuntu,它也返回0。即使read()返回-1,下面的代码也是可疑的。如果strlen(buf)==0怎么办?然后buf[strlen(buf)-1]
行吗?@eryksun我给你的标准规范链接说“如果设置了ICANON,处理时将丢弃EOF字符。“。如果WSL无法做到这一点,则必须使用TCIFLUSH
手动放弃EOF字符。使用TCSET*
来回更改tty模式也可能会导致副作用。但这两种情况都不是必需的(在任何Unix系统上都不是)。