Strange phenomenon of console input to a C program
我正在使用Visual Studio 2010运行以下简单程序。目的是看看如果我将变量c定义为char或int,会发生什么,因为getchar()函数返回一个整数(C编程语言中众所周知的陷阱,请参阅int c=getchar()?).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include <stdio.h>
int main ()
{
char c ;
//int c;
while((c = getchar()) != EOF )
putchar(c );
printf("%d
",c );
return 0;
} |
当我从控制台向这个程序输入一些字符时,发现了一个奇怪的现象,如下图所示。如果输入的EOF遵循字符序列(第一行),则无法正确识别(右小箭头为ouput,第二行)。但是,如果它是独立输入的(第4行),则可以正确识别它并终止程序。
我没有在Linux上测试这个程序,但是有人能解释为什么会发生这种情况吗?
- 这种行为与宣布c为int时的行为不同吗?
- @拉尔曼不,不是。如果c是int类型,我得到了同样的结果。
- 尝试键入&255;(y-umlaut,拉丁文小写字母y,带分音符,u+00ff);我希望您的程序在使用char c;时也停止读取该字符,但实际上不应该这样做。如果你使用int c;就可以了。记住:getchar()返回int!
- @jonathanlefler是的,getchar()返回int,我知道这里把c定义为char是一个bug。但这不是我想讨论的重点,我想知道为什么在控制台中无法正确识别EOF字符。
您所描述的基本上是终端的设计方式。
您需要记住,EOF不是一个字符。键入"abcdefctrl zakbd"时,将输入八个输入字符:a、b、c、d、e、f、ctrl zakbd和return。CtrlZakbd(或CtrlDakbd,在Unix/Linux上)唯一的特殊之处是,如果您在新行中键入它作为第一个内容,那么终端的行为就好像输入文件的结尾已经到达一样,而不是输入字符。getchar()函数将返回EOF。由于任何可以放入unsigned char中的可能值都是getchar()的有效返回值,因此EOF可以通过为负数区别于任何有效返回值,这就是getchar()和family被定义为返回int的原因。
- 谢谢你的回答,但它仍然不能解释为什么当EOF跟在某些字符后面时不能正确识别,即不在单独的行中。
- 因为它就是这样设计的。当您按下用于发出EOF信号的键(control-z或control-d或其他任何键)时,它只被视为一条线开始时的EOF信号。从根本上说,它是这样工作的,因为它的设计就是这样工作的,基本上就是这样。是的,在Unix上也会看到同样的行为。
- 我明白了,谢谢!很奇怪,我没有读过任何书告诉我,EOF应该是独立的一行。
如果您稍微更改一下程序,并放入两个printf语句,您将看到程序实际上可以正确读取crtl+z组合(ASCII代码26):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| |
但是正如上面的答案所说,它必须在它自己的线上;为了被正确地解释。因为在Windows上,除了最后一行外,每行都有一个EOL字符。最后一行后面有一个EOF字符。
- 嗯,我很困惑。事实上,在dubug模式下,我已经看到c的值是26,但我认为这是因为没有正确识别EOF。我预计当输入EOF时,c将是-1,因为默认情况下,c在vs 2010中是signed char的(我相信在gcc中也是如此),这就是为什么大多数时候将c定义为char不会导致错误的原因,如果输入字符都是英文字符。
- 还有,你能再解释一下关于EOL的事吗?
- 不,根据ASCII表,ctrl+z的实际值是26,在C中使用该值是正确的行为。看看这个页面:rabbit.eng.miami.edu/class/een218/getchar.html
- 行尾(eol)字符(0x0D0A),实际上是两个ASCII字符,是CR和LF字符的组合。它将光标向下移动到下一行和该行的开头。此字符在大多数其他非UNIX操作系统(包括Microsoft Windows、Symbian OS和其他操作系统)中用作新行字符。
- 啊,我知道以东王〔12〕,但我不知道叫以东王〔11〕。还有一个问题:既然有两个字符,为什么getchar()只读取换行符(),而忽略回车符()?Windows上的C编译器是否将CRLF作为一个整体并将其视为
?我知道Linux和Mac上的eol是
。
- 我认为这是一个标准问题,它规定了如何映射一组特殊的字符。我认为,由于标准的原因,实现在返回时必须映射到
,在打印时必须再次映射到
。我认为这是一个实施问题。最好看一下实现和标准,找到这个问题的确切答案。