【问题标题】:BWK's C Tutorial - while(putchar(getchar()) != EOF) ignores EOF [duplicate]BWK 的 C 教程 - while(putchar(getchar()) != EOF) 忽略 EOF [重复]
【发布时间】:2021-12-13 23:54:30
【问题描述】:

我正在阅读 Brian Kernighan 的 Programming in C - A Tutorial,他在第 5 页上建议

main( ) {
    char c;
    while( (c=getchar( )) != ′\0′ )
        putchar(c);
}

可以简化为

main( ) {
    while( putchar(getchar( )) != ′\0′ ) ;
}

唯一的区别是最后一个'\0' 打印在第二个。

但是,当我编译它时,将 '\0' 替换为 EOF,并传递一个字符串:$ printf "abc" | ./a.out,程序进入一个无限循环,打印 ASCII 0xff 字符。

如果我将其更改为while( putchar(getchar( )) != 'd' ) ; 并运行$ printf "abcde" | ./a.out,它会成功打印到d(包括d),然后退出。

为什么它会进入无限循环而不是打印abc(EOF) 并退出?

【问题讨论】:

  • Dude - "EOF" "\0'!如果你查看 stdio.h,你会看到它是 "-1"。问:如果你只是逐字复制示例,一切正常吗?
  • 我用 '\0' 和 -1 (没有引号)都试过了。一旦它到达 EOF(^D、文件描述符结尾、字符串结尾等),它就会开始发送垃圾邮件 0xff。
  • 替代代码:int main( ) { int c; while( (c=getchar( )) != EOF ) putchar(c); } }

标签: c


【解决方案1】:

EOF 是一个具有负值的宏,它取决于实现(通常为 -1)。如果您查看 putchar(3) 的手册页,您可以看到 putchar() 将作为参数提供的字符写入,将无符号字符转换为标准输出,并将作为无符号字符转换为 int 或 EOF 错误时写入的字符返回。

getchar() 在标准输入的末尾返回 EOF 时,putchar() 将此值强制转换为 unsigned char,将其写入标准输出并将 unsigned char 值强制转换为 int。因此,如果 EOF 等于 -1,则示例中的 putchar() 将返回 255(-1 转换为 unsigned char,然后转换为 int)。如果在 while 循环中将 '\0' 替换为 EOF,您将得到一个无限循环,因为 255 != EOF。

【讨论】:

    【解决方案2】:

    根据§7.21.7.8 of the ISO C11 standard,函数putchar 会将其int 参数转换为unsigned char 并写入该字符,并返回该字符(不是原始未转换的int 参数)。

    因此调用putchar( EOF ) 将返回(unsigned char)EOF,它不能等于EOF(因为EOF 必须是负值)。

    为此,在行中

    while( putchar( getchar() ) != EOF )
    

    循环条件永远为真,这样你就会有一个无限循环。

    请注意,EOF 不是一个实际字符,而只是一个特殊的宏常量,用于指示错误或文件结束条件。

    【讨论】:

    • 我想这终于解释了。
    【解决方案3】:

    这是一个非常古老的教程;你可以知道,因为它没有为main 指定返回类型。但它真正的问题是它循环直到getchar返回0(也称为'\0'),但实际上getchar会在文件末尾返回EOF,也就是等于@987654326 @ 在我的系统上(也可能是你的)。

    显然,在编写该教程时,getchar 将在文件末尾返回 0。不过,这不是很好的行为,因为它使处理通常包含许多 0 字节的二进制数据变得很棘手。在某些时候,语言发生了更改,getchar 更改为返回 int 而不是 char,并在文件末尾返回 EOF

    【讨论】:

    • 还有一个次要问题:putchar(getchar()) != EOF 仅在 putchar() 遇到错误时发生——否则它会将其参数掩码为字符大小,所以当 getchar()返回-1,putchar() 返回0xff。
    • @mevets 解决了!我检查了!= 0xff,它打印了一个 0xff 并退出。
    • 那没有解决;那是错误;这就是为什么程序必须是:int c; while ((c=getchar()) != EOF) putchar(c); 注意int 和有目的地避免打印0xff
    • 我猜没有办法只使用这个嵌套表达式打印一个干净的 EOF 而不是 0xff。
    • EOF 不是字符(与 DOS, CPM 系统不同,^Z 标记为 EOF)。 EOF 是您正在读取的数据源的条件。当它是一个文件时,那是因为您已经读取了该文件。当它是tty-like 设备时,当用户输入一个字符时,设备管理软件将其解释为输入结束。在unix 派生系统中,默认为^D,但可以通过sttytcsetattr 设置为任何字符。
    猜你喜欢
    • 2013-09-05
    • 1970-01-01
    • 1970-01-01
    • 2012-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多