使用EOF结束循环(不输入)

Mic*_*ler 4 c linux windows eof

我目前正在尝试使用以下内容结束while循环:

#include <stdio.h>
int main() 
{
    while(getchar() != EOF)
    {
        if( getchar() == EOF )
            break;
    }
    return 0;
Run Code Online (Sandbox Code Playgroud)

}

当我按下CTRL+D我的Ubuntu时,它会立即结束循环.但在Windows上,我必须按CTRL+Z,然后按ENTER关闭循环.我可以摆脱ENTERWindows吗?

Mat*_*gni 7

getchar的行为

对于linux,EOF字符用ctrl+ 编写d,而在Windows上,当您enter通过ctrl+ 更改CRT库的内部状态后按下时,它由控制台编写z(此行为保留用于与旧系统的后向兼容性).如果我没错,它被称为软文件结尾.我不认为你可以绕过它,因为EOF字符实际上是getchar你按下时消耗的enter,而不是当你按ctrl+时z.

据报道在这里:

在Microsoft的DOS和Windows(以及CP/M和许多DEC操作系统)中,从终端读取将永远不会产生EOF.取而代之的是,节目识别出源是一个终端(或其他"字符设备")和解释给定保留的字符或序列作为指示剂文件结束-; 最常见的是这是一个ASCII Control-Z,代码26.一些MS-DOS程序,包括Microsoft MS-DOS shell(COMMAND.COM)和操作系统实用程序(如EDLIN)的一部分,处理Control-Z在文本文件中标记有意义数据的结尾,和/或在写入文本文件时将Control-Z附加到末尾.这样做有两个原因:

  • 向后兼容CP/M. CP/M文件系统仅以128字节"记录"的倍数记录文件长度,因此按照惯例,如果有意义数据在记录中间结束,则使用Control-Z字符标记有意义数据的结尾.MS-DOS文件系统始终记录文件的确切字节长度,因此在MS-DOS上永远不需要这样做.

  • 它允许程序使用相同的代码从终端和文本文件中读取输入.

其他信息也在这里报告:

一些现代文本文件格式(例如CSV-1203 [6])仍然建议将尾随的EOF字符作为文件中的最后一个字符追加.然而,键入控制+ Z没有嵌入的EOF字符到任何MS-DOS或Microsoft Windows中的文件,也没有这些系统的API使用的字符来表示文件的实际结束.

当使用内置文本文件读取基元(INPUT,LINE INPUT等)时,某些编程语言(例如Visual Basic)将无法读取"软"EOF,并且必须采用替代方法,例如以二进制模式打开文件或者使用文件系统对象来超越它.

字符26用于标记"文件结束",即使ASCII称之为替换,并且具有其他字符.

如果你修改你的代码:

#include <stdio.h>

int main() {
  while(1) {
    char c = getchar();
    printf("%d\n", c); 
    if (c == EOF)      // tried with also -1 and 26
      break;
  }
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

并且你测试它,在Windows上你会看到EOF(-1)它没有写在控制台中,直到你按下enter.那个a的beore ^Z是由终端模拟器打印的(我怀疑).从我的测试中,如果出现以

  • 您使用Microsoft编译器进行编译
  • 你使用GCC编译
  • 您在CMD窗口中运行已编译的代码
  • 您在Windows中的bash模拟器中运行已编译的代码

使用Windows控制台API进行更新

根据@eryksun的建议,我成功地为Windows编写了一个(可以做的很复杂的代码)代码,它改变了conhost的行为,实际上在按下ctrl+ 时"退出d".它不处理所有事情,它只是一个例子.恕我直言,这是尽可能避免的事情,因为可移植性小于0.此外,要实际正确处理其他输入案例,应编写更多代码,因为这些东西将stdin与控制台分离,你必须自己处理.

这些方法或多或少地起作用如下:

  • 获取标准输入的当前处理程序
  • 创建一个输入记录数组,这个结构包含有关conhost窗口中发生的事情的信息(键盘,鼠标,调整大小等)
  • 阅读窗口中发生的事情(它可以处理事件的数量)
  • 遍历事件向量来处理键盘事件并截取所需EOF(这是一个如图4所示,从我测试)用于退出,或打印任何其他ASCII字符.

这是代码:

#include <windows.h>
#include <stdio.h>

#define Kev input_buffer[i].Event.KeyEvent // a shortcut

int main(void) {
  HANDLE h_std_in;                // Handler for the stdin
  DWORD read_count,               // number of events intercepted by ReadConsoleInput
        i;                        // iterator
  INPUT_RECORD input_buffer[128]; // Vector of events

  h_std_in = GetStdHandle( // Get the stdin handler
    STD_INPUT_HANDLE       // enumerator for stdin. Others exist for stdout and stderr
  ); 

  while(1) {
    ReadConsoleInput( // Read the input from the handler
      h_std_in,       // our handler 
      input_buffer,   // the vector in which events will be saved
      128,            // the dimension of the vector
      &read_count);   // the number of events captured and saved (always < 128 in this case)

    for (i = 0; i < read_count; i++) {    // and here we iterate from 0 to read_count
      switch(input_buffer[i].EventType) { // let's check the type of event 
        case KEY_EVENT:                   // to intercept the keyboard ones
          if (Kev.bKeyDown) {             // and refine only on key pressed (avoid a second event for key released)
            // Intercepts CTRL + D
            if (Kev.uChar.AsciiChar != 4)
              printf("%c", Kev.uChar.AsciiChar);
            else
              return 0;
          }
          break;
        default:
          break;
      }
    }
  }

  return 0;
}
Run Code Online (Sandbox Code Playgroud)