GetChar()即使在随后的呼叫后仍会返回EOF,但读取()系统呼叫似乎是“清晰的” stdin。背后的原因是什么?

发布于 2025-01-24 21:17:28 字数 1221 浏览 5 评论 0原文

char buff[1];

int main() {
    int c;
    c = getchar();
    printf("%d\n", c); //output -1

    c = getchar();
    printf("%d\n", c); // output -1

    int res;

    //here I get a prompt for input. What happened to EOF ?
 
    while ((res = read(0, buff, 1)) > 0) { 
        printf("Hello\n");
    }

    while ((res = read(0, buff, 1)) > 0) {
        printf("Hello\n");
    }

    return 0;
}

代码中使用注释的行显示的结果输出是简单地键入 ctrl-d (MacOS上的eof)。

我对getchar()的行为有些困惑,尤其是与读取相比。

  1. 是否应该读取 内的系统调用循环也返回eof?他们为什么提示用户?是否发生过某种stdin明确发生了?

  2. 考虑到getchar()使用读取在引擎盖下的系统调用,他们的行为如何有所不同? stdin不应该是“唯一”,而eof共享条件?

  3. 如何在以下代码中获得两个读取系统调用返回eof当给出 ctrl-d 输入时?

    int res;

    while ((res = read(0, buff, 1)) > 0) {
        printf("Hello\n");
    }

    while ((res = read(0, buff, 1)) > 0) {
        printf("Hello\n");
    }

我试图在所有这些背后找到逻辑。希望某人可以清楚地表明eof真正的行为方式。

PS我正在使用Mac OS机器

char buff[1];

int main() {
    int c;
    c = getchar();
    printf("%d\n", c); //output -1

    c = getchar();
    printf("%d\n", c); // output -1

    int res;

    //here I get a prompt for input. What happened to EOF ?
 
    while ((res = read(0, buff, 1)) > 0) { 
        printf("Hello\n");
    }

    while ((res = read(0, buff, 1)) > 0) {
        printf("Hello\n");
    }

    return 0;
}

The resulting output showed with commented lines in the code is the result of simply typing Ctrl-D (EOF on macOS).

I'm a bit confused about the behaviour of getchar(), especially when compared to read.

  1. Shouldn't the read system calls inside the while loop also return EOF? Why do they prompt the user? Has some sort of stdin clear occurred?

  2. Considering that getchar() uses the read system call under the hood how come they behave differently? Shouldn't the stdin be "unique" and the EOF condition shared?

  3. How come in the following code the two read system calls return both EOF when a Ctrl-D input is given?

    int res;

    while ((res = read(0, buff, 1)) > 0) {
        printf("Hello\n");
    }

    while ((res = read(0, buff, 1)) > 0) {
        printf("Hello\n");
    }

I'm trying to find a logic behind all this. Hope that someone could make it clear what EOF really is a how it really behaves.

P.S I'm using a Mac OS machine

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

迷乱花海 2025-01-31 21:17:28

一旦设置了 stdingetchar()不尝试阅读。

清除文件终止指示器(例如clearerr()或其他)重新读取。

getchar函数等于getc带有参数stdin

getc功能等于fgetc ...

如果未设置输入流的文件终止指示器,并且存在下一个字符,则fgetc函数将该字符作为未符号char转换为int,并为流的相关文件位置指示器(如果定义)。


read()仍尝试每次读取。


注意:通过文件 *读取,例如stdin,如果设置了文件终止指示器,则不会尝试阅读。但是,即使设置了错误指示器,仍会发生读取尝试。

Once the end-of-file indicator is set for stdin, getchar() does not attempt to read.

Clear the end-of-file indicator (e.g. clearerr() or others) to re-try reading.

The getchar function is equivalent to getc with the argument stdin.

The getc function is equivalent to fgetc ...

If the end-of-file indicator for the input stream pointed to by stream is not set and a next character is present, the fgetc function obtains that character as an unsigned char converted to an int and advances the associated file position indicator for the stream (if defined).

read() still tries to read each time.


Note: Reading via a FILE *, like stdin, does not attempt to read if the end-of-file indicator is set. Yet even if the error indicator is set, a read attempt still occurs.

他夏了夏天 2025-01-31 21:17:28

MACOS是BSD Unix系统的衍生产品。它的STDIO实现不是来自GNU软件,因此是不同的实现。在EOF上,发出读取(2)系统调用并接收0作为读取的字符数时,文件描述符被标记为错误2)再次直至重置错误条件,并产生您观察到的行为。在发出下一个getchar(3)调用之前,请使用clearerr(stream);文件 *描述符上使用,一切都很好。您也可以使用GLIB来执行此操作,然后,您的程序将在STDIO的任何一个实施中运行(GLIB vs. BSD)

我试图在所有这些背后找到逻辑。希望有人可以清楚地表明它的真正行为是什么。

eof只是一个常数(通常为-1),它与任何可能的char> char值由getchar(3)(<)代码> getchar()在0..255中返回int,而不是为此目的返回char,以扩展范围OS可能具有一个可能的字符,以代表EOF条件,但EOF不是一个char)文件条件的结束是由getchar函数家族(getchar,fgetC等)表示的,因为文件的结束是由read> read(2)发出的。返回值为0(返回字符的数量为零),该值不会映射为某些字符。...因此,可能的字符数被扩展到整数和新值eof定义为在到达文件状态结束时返回。这与具有CTRL-D字符(ASCII EOT或CNTRL-D,十进制值4)的文件兼容,并且不表示文件状态的结尾(当您从文件中读取ASCII EOT时4)

另一侧的UNIX TTY实现允许在线输入模式使用特殊字符(CTRL-D,ASCII EOT/传输末端,小数值4),以指示流和末端到驱动程序... 。没有读取的内容,您将获得文件的末尾),因此请认为cntrl-d仅在UNIX TTY驱动程序中仅是特殊,并且仅当它以规范模式(行输入模式)工作时。因此,最后,只有两种方法可以在行模式下将数据输入程序:

  • 按返回键(由终端映射到ASCII CR中,终端将其转换为ASCII LF,著名'\ n '字符),ASCII LF字符输入到程序
  • 按下CTRL-D键。这使得终端可以抓住直到本时的所有内容并将其发送到程序(不添加CTRL-D本身),并且没有将字符添加到输入缓冲区中,这意味着,如果输入缓冲区是空的,没有发送到程序读取(2)呼叫从缓冲区有效地读取零字符。

为了在每种情况下统一,读取(2)系统调用通常会阻止内核直到一个或多个字符可用。...该程序。这应该是您的文件指示。许多程序读取不完整的缓冲区(小于您作为参数传递的字符数),然后在文件的真实末尾发出信号之前,因此,几乎每个程序都会读取另一个程序以检查是否是不完整的读数,或者确实是结束文件指示。

最后,如果我想将CNTRL-D字符作为文件输入CNTRL-D字符。...TTY实现中还有另一个特殊字符,可以使您能够逃脱此前面的特殊字符上的特殊行为。在当今的系统中,该字符默认是CTRL-V,因此,如果要输入特殊字符(甚至是?ctrl-v),则必须使用CTRL-V之前使用它,使得将CTRL-D输入到文件中才能必须输入CTRL-V + CTRL-D。

MacOs is a derivative of BSD unix systems. Its stdio implementation does not come from GNU software and so it is a different implementation. On EOF, the file descriptor is marked as erroneous when issuing a read(2) system call and receiving 0 as the number of characters returned by read, and so, it doesn't read(2) it again until the error condition is reset, and this produces the behaviour you observe. Use clearerr(stream); on the FILE * descriptor before issuing the next getchar(3) call, and everything will be fine. You can do that with glib also, and then, your program will run the same in either implementation of stdio (glib vs. bsd)

I'm trying to find a logic behind all this. Hope that someone could make it clear what EOF really is a how it really behaves.

EOF is simply a constant (normally it's valued as -1) that is different to any possible char value returned by getchar(3) (getchar() returns an int in the interval 0..255, and not a char for this purpose, to extend the range os possible characters with one more to represent the EOF condition, but EOF is not a char) The end of file condition is so indicated by the getchar family of functions (getchar, fgetc, etc) as the end of file condition is signalled by a read(2) return value of 0 (the number of returned characters is zero) which doesn't map as some character.... for that reason, the number of possible chars is extended to an integer and a new value EOF is defined to be returned when the end of file condition is reached. This is compatible with files that have Ctrl-D characters (ASCII EOT or Cntrl-D, decimal value 4) and not representing an END OF FILE condition (when you read an ASCII EOT from a file it appears as a normal character of decimal value 4)

The unix tty implementation, on the other side, allows on line input mode to use a special character (Ctrl-D, ASCII EOT/END OF TRANSMISSION, decimal value 4) to indicate and end of stream to the driver.... this is a special character, like ASCII CR or ASCII DEL (that produce line editing in input before feeding it to the program) in that case the terminal just prepares all the input characters and allows the application to read them (if there's none, none is read, and you got the end of file) So think that the Cntrl-D is only special in the unix tty driver and only when it is working in canonical mode (line input mode). So, finally, there are only two ways to input data to the program in line mode:

  • pressing the RETURN key (this is mapped by the terminal into ASCII CR, which the terminal translates into ASCII LF, the famous '\n' character) and the ASCII LF character is input to the program
  • pressing the Ctrl-D key. this makes the terminal to grab all that was keyed in upto this moment and send it to the program (without adding the Ctrl-D itself) and no character is added to the input buffer, what means that, if the input buffer was empty, nothing is sent to the program and the read(2) call reads effectively zero characters from the buffer.

To unify, in every scenario, the read(2) system call normally blocks into the kernel until one or more characters are available.... only at end of file, it unblocks and returns zero characters to the program. THIS SHOULD BE YOUR END OF FILE INDICATION. Many programs read an incomplete buffer (less than the number of characters you passed as parameter) before a true END OF FILE is signalled, and so, almost every program does another read to check if that was an incomplete read or indeed it was an end of file indication.

Finally, what if I want to input a Cntrl-D character as itself to a file.... there's another special character in the tty implementation that allows you to escape the special behaviour on the special character this one precedes. In today systems, that character is by default Ctrl-V, so if you want to enter a special character (even ?Ctrl-V) you have to precede it with Ctrl-V, making entering Ctrl-D into the file to have to input Ctrl-V + Ctrl-D.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文