我读到过Ctrl-J发送 '\n',Ctrl-M发送 '\r' 和Ctrl-D发送 EOF,但这要么是错误的,要么就是我根本不明白发生了什么。这个简单的程序说明了:
const size_t SIZE = 100;
int main()
{
char str[SIZE];
printf("Enter string: ");
size_t len = 0;
char ch;
while ((ch = getchar()) != '\r' && ch != '\n' && ch != EOF && len < SIZE -1)
{
str[len++] = ch;
printf("ch is %i\n",ch);
}
printf("ch is %i\n",ch);
str[len] = '\0';
printf("%s\n",str);
return 0;
}
当我输入:hello(Ctrl-j)时,输出正是我所期望的:
ch is 104
ch is 101
ch is 108
ch is 108
ch is 111
ch is 10
hello
但是当我输入:hello(Ctrl-m)时输出完全相同 - 即最后一个ch仍然是10,而不是我期望的13。
当我输入:hello(Ctrl-d)时,输出在“ch is 111”('o')后面的行首停止:
ch is 101
ch is 108
ch is 108
ch is 111
并等待,直到我第二次按下 Ctrl-d 之后它完成:
ch is -1
hello
或者,如果我按的是-或,而不是第二个Ctrl- 。在这种情况下,它以DCtrlJEnter
[blank line]
ch is 10
hello
丢失 -1 并打印 10 作为 '\n'。
我已经在运行 Arch Linux 的台式机和运行 Ubuntu 的笔记本电脑上尝试过此操作——两者的结果相同。
那么,在 Linux 下是否真的有办法从键盘发送 CR,为什么需要发送两次 EOF?
答案1
那么,在 Linux 下有没有办法从键盘发送 CR
你是发送 CR,但 tty 层会默认将其转换为 LF,因此程序无法收到CR。如果要避免这种情况,请使用tcsetattr()
禁用该模式。(但不要忘记先保存旧设置,然后在退出时重置它们。)ICRNL
同时搜索生/熟/cbreak模式。
为什么EOF需要发送两次?
实际上,在操作系统级别上不存在 EOF 结果这样的事情 - 相反,每当 read() 系统调用返回 0 字节时,libc 函数就会将其报告为 EOF。
因此 Ctrl+D 实际上只是告诉操作系统立即完成 read() 调用(即不等待换行符),并且只有当它导致 read() 调用完全不返回任何数据时,它才会成为 EOF 指示符。只有在换行符后立即按下它时才会发生这种情况或者在先前按下 Ctrl+D 之后。
您也会在其他程序中看到这种情况。运行strace -e read cat
或strace -e read ./myprogram
以更详细地查看它发生的情况。