我最近开始从 K&R 书中学习 C。现在我卡在示例 1.5.2 上了。程序是这样的:
#include <stdio.h>
/* Count the number of characters written in input */
main()
{
long nc;
nc = 0;
while (getchar() != EOF)
nc++;
printf("%ld\n", nc);
}
我通过 NppExec 插件直接从 notepad++ 编译代码,但也尝试直接从 cmd 运行它。
这是不同的例子
示例 1:
input: dadada^Z
来自 Notepad++
output: 0
来自命令
while loop doesn't end
示例 2:
input: dadada[enter]^Z
来自 Notepad++
output: 7
来自命令
while loop doesn't end
示例 3:
input: dadada[enter]^Z[enter]
来自 Notepad++
output: program end with [enter]^Z, additional [enter] doesn't do anything
来自命令
output: 7
现在我想知道为什么示例 1 中的输出为 0。
谁能解释一下 EOF
整数。在cmd中是[enter]^Z[enter]
,在notepad++中是[enter]^Z
,甚至有人说是^Z
.
编辑
这是我在NppExec中使用的命令
npp_console 1 //open console
NPP_CONSOLE - //disable output of commands
npe_console m- //disable unnecessary output
con_colour bg= 191919 fg= F5F5F5 //set console colors
npp_save //save the file
cd $(CURRENT_DIRECTORY) //follow current directory
NPP_CONSOLE + //enable output
IF $(EXT_PART)==.c GOTO C //if .c file goto C label
IF $(EXT_PART)==.cpp GOTO CPP //if .cpp file goto CPP label
IF $(EXT_PART)==.java GOTO JAVA //if .java file goto JAVA label
IF $(EXT_PART)==.cs GOTO C# //if .cs file goto C# label
IF $(EXT_PART)==.py GOTO PYTHON //if .py file goto PYTHON label
echo FILE SAVED
GOTO EXITSCRIPT // else treat it as a text file and goto EXITSCRIPT
//C label
:C
cmd /C if exist "$(NAME_PART).exe" cmd /c del "$(NAME_PART).exe"//delete existing executable file if exists
gcc "$(FILE_NAME)" -o $(NAME_PART) //compile file
IF $(EXITCODE) != 0 GOTO EXITSCRIPT //if any compilation error then abort
echo C CODE COMPILED SUCCESSFULLY: //print message on console
$(NAME_PART) //run file in cmd, set color to green and pause cmd after output
GOTO EXITSCRIPT //finally exits
:CPP
cmd /C if exist "$(NAME_PART).exe" cmd /c del "$(NAME_PART).exe"
g++ "$(FILE_NAME)" -o $(NAME_PART)
IF $(EXITCODE) != 0 GOTO EXITSCRIPT
echo C++ CODE COMPILED SUCCESSFULLY:
$(NAME_PART)
GOTO EXITSCRIPT
:JAVA
cmd /C if exist "$(NAME_PART).class" cmd /c del "$(NAME_PART).class"
javac $(FILE_NAME) -Xlint
IF $(EXITCODE) != 0 GOTO EXITSCRIPT
echo JAVA CODE COMPILED SUCCESSFULLY:
java $(NAME_PART)
GOTO EXITSCRIPT
:C#
cmd /C if exist "$(NAME_PART).exe" cmd /c del "$(NAME_PART).exe"
csc $(FILE_NAME)
IF $(EXITCODE) != 0 GOTO EXITSCRIPT
echo C# CODE COMPILED SUCCESSFULLY:
$(NAME_PART)
GOTO EXITSCRIPT
:PYTHON
echo RUNNING PYTHON SCRIPT IN CMD: //python is a script so no need to compile
python $(NAME_PART).py
GOTO EXITSCRIPT
:EXITSCRIPT
// that's all, folks!
最佳答案
编辑:我现在看到您使用 gcc,我意识到也许编译器(确定运行时库)可能不是那么重要。它只会在 read()
或来自文件描述符的等效项上收到零返回值。用户输入如何触发是终端(输入窗口和驱动程序)的问题。
unix网上有很好的解释;一个相当彻底的是here . (与我之前的想法相反,shell 不参与其中;shell 不处理从终端到前台程序的输入。)底线是终端程序和驱动程序一起对某些用户操作使用react(就像按下一个特殊的按钮,或者选择一个菜单项),然后“传达事物”(关闭文件描述符,发送信号)到正在运行的进程[组]。 Windows 机制可能几乎但并非完全不同。
然后,根据 documentation,nppexe 插件不是真正的终端。 ;我不知道在什么情况下它会关闭将数据发送到的文件描述符(使读取过程检测到 EOF 的事件)。我必须假定当您按下 ctrl-z 而没有发送到目前为止键入的字符时它会关闭文件描述符。
普通的 Windows 控制台通常将 ctrl-z 识别为文件结束指示器,但有限制(参见 Cool Guy 的评论)。在我使用 cygwin-gcc 编译程序在 Windows 控制台上进行的尝试中,ctrl-z 立即关闭与程序的通信,丢弃当前输入行上的任何用户输入。这与您的 0 结果一致。
cygwin 终端(我使用 mintty)和 shell(我使用 bash)通常会识别 ctrl-d。在那里,也必须在一行的开头按下 ctrl-d,或者更确切地说,当到目前为止的所有输入都已发送时。如果在按下 ctrl-d 时输入处于挂起状态,例如在键入一行时,它会导致终端将该数据发送到进程,因此不再有数据等待。因此,随后的第二个 ctrl-d 将使终端关闭连接。 (感谢 Chrono 指出这一点。)
(Ctrl-z 通常被 unix 终端以及 cygwin 的 mintty 解释为暂停当前前台进程的请求。请注意,这些特殊键可通过 stty
配置:stty eof ^E
,其中 ctrl-e 是通过按 ctrld-v ctrl-e 产生的,从那时起将使终端识别 ctrl-e 而不是 ctrl-d 作为文件结尾。)
一般来说,我建议使用重定向到程序标准输入的准备文件来测试此类程序。这避免了交互式 session 中涉及的许多陷阱,并具有可完美重现和自动运行的优点,这对测试很重要。
关于c - K&R 字符计数程序打印 0,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35101194/