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

时间:2017-10-26 09:15:40

标签: c linux windows eof

我目前正试图用这样的东西结束一个while循环:

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

}

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

2 个答案:

答案 0 :(得分:7)

getchar行为

对于linux,EOF字符用 ctrl + d 编写,而在Windows上,当你按输入后由控制台写入通过 ctrl + z 更改CRT库的内部状态(保留此行为是为了与非常旧的系统进行后向兼容)。如果我没错,那就称为文件的软端。我不认为你可以绕过它,因为当你按输入时,你的getchar实际上消耗了EOF字符,而不是按 ctrl + < KBD>ž

据报道here

  

在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上永远不需要这样做。

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

  •   

其他信息也会报告here

  

某些现代文本文件格式(例如CSV-1203 [6])仍建议将尾随EOF字符作为文件中的最后一个字符追加。但是,键入Control + 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;
}

并且你测试它,在Windows上你会看到EOF( - 1)它没有写入控制台,直到你按 enter 。 Beore of a ^Z由终端模拟器打印(我怀疑)。从我的测试中,如果出现以下情况,则会重复此行为:

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

使用Windows控制台API进行更新

根据@eryksun的建议,我成功地为Windows编写了一个(可笑的复杂功能)代码,它改变了conhost的行为,实际上在按下 ctrl + <时出现了“退出” KBD> 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;
}

答案 1 :(得分:0)

    while(getchar() != EOF)
    {
        if( getchar() == EOF )
            break;
    }
    return 0;

这里不一致。

如果getchar() != EOF它将进入循环,否则(如果getchar() == EOF)它将不会进入循环。因此,没有理由在循环中检查getchar() == EOF

另一方面,您拨打getchar() 2次,等待输入2个字符而不是1个。

你尝试做什么?