【问题标题】:EOF symbolic constantEOF 符号常数
【发布时间】:2013-11-12 00:14:03
【问题描述】:

来自C 编程语言

int c;
while ((c = getchar()) != EOF)
    putchar(c);

"... 解决方案是getchar在没有更多输入时返回一个独特的值,这个值不能与任何真实字符混淆。这个值称为EOF,表示“文件结束。 " 我们必须将c 声明为一个足够大的类型,以容纳getchar 返回的任何值。我们不能使用char,因为c 必须足够大以容纳EOF 以及任何可能的@ 987654331@。”

我签入stdio.h 并在我的系统上打印了EOF 的值,它设置为-1。在我的系统上,chars 已签名,尽管我知道这取决于系统。所以,EOF 可以适合我的系统的char。我重写了上面的小例程,将c 定义为char,程序按预期工作。在 ASCII 字符表 here 中还有一个字符,它似乎有一个对应于 255 的空白字符,其行为类似于 EOF

那么,为什么 ASCII 似乎有一个指定为 EOF 的字符 (255)?这似乎与 The C Programming Language 书中所说的相矛盾。

【问题讨论】:

标签: c eof


【解决方案1】:

getchar() 读取字节 255 时,返回 255。getchar() 发现没有更多输入时,返回 -1。

如果将结果存储在char 中,则无法区分两者。但是,当您将它们存储在int 中时,您可以。 (此声明独立于char 的签名)。

只有当您知道结果有效时,您才能将其转换为char 并获得通常的 C 样式字符类型。

【讨论】:

    【解决方案2】:

    那么,为什么 ASCII 似乎有一个指定为 EOF 的字符 (255)?

    它没有。更准确地说,这不是 EOF “字符”。

    诀窍是,getchar() 将始终返回非负值,如果它有要读取的内容。如果遇到文件结束,它只会返回 -1(这就是 EOF 似乎在您的实现中定义的)。

    char 的事实是:

    1. 8 位宽,
    2. 签名并
    3. 使用 2 的补码表示,

    只是您实现的一个怪癖(尽管现在非常普遍)。因此,如果您使用char 来存储getchar() 的返回值,那么读取输入可能会提前终止:代码为255 的字符将被误认为是-1 a。 ķ。一种。 EOF这是一个错误。这就是发生在你身上的事情。 它不起作用——相反,你的第二种方法完全被打破了。

    【讨论】:

    • 旁注:存在一个名为“EOF”的 ASCII 字符,值为 26 (0x1a),但这与问题无关。
    • EOF 取决于系统,所以我相信我们会找到其他变体。
    • @givanse 是的,但EOF要求按标准为负数。
    • @H2CO3 只是好奇,但是在您检查字符是否有效之后,将其存储在char 中是否会出现任何问题,因为可能会发生溢出(如果char 已签名)?跨度>
    • @jucestain 有符号整数溢出是由算术运算符引起的未定义行为(参见this question/answer),但不是由初始化引起的,所以我认为char ch = i; 应该没问题。
    【解决方案3】:

    根据 getchar() 的手册,它总是返回 int 值:

    #include <stdio.h>
    ...
    int getchar(void);
    ...
    RETURN VALUE
    fgetc(), getc() and getchar() return the character read as 
    an unsigned char cast to an int or EOF on end of file or error.
    

    因此使用 char 代替 int 会导致截断(int -1 (0xffffffff) 变为 char -1 (0xff))并可能导致错误。

    【讨论】:

    • 谢谢,我最初的问题是我没有意识到getchar 将一个字节读取为unsigned char,然后将其转换为int。意识到这一点后,返回-1' for EOF` 是有意义的。
    【解决方案4】:

    要了解其工作原理,想象一下编写 getchar 的人的想法。你需要读取一个文件。首先创建一个例程 - 例如:

    unsigned char get_me_a_byte(file)... // 0..255
    

    现在你想从文件中读取所有字节:

    unsigned char c;
    
    while( c = get_me_a_byte(file) ) // while( (c = get_me_a_byte(file)) != 0 )
    {
      ... do sth
    }
    

    问题是它会在遇到 z 零时停止,但你想在一切都变红时停止。 现在你变得更聪明了——你知道文件可以被认为是字节序列。 如果您的 get_me_a_byte 可以返回 16 位或 32 位类型怎么办?然后你可以使用一些字节不能保存的值作为文件结束标记。

    宾果游戏

    既然决定是你的,你可能有:

    int get_me_a byte_U(file) ... // returning bytes as 0..255
    int get_me_a byte_S(file) ... // returning bytes as -128..127
    

    现在你可以这样做了:

    int c;
    while( (c = get_me_a_byte_U(file) != UUU ) ....
    

    其中 UUU 可以是您平台上从 256 到 MAXINT 的任何值

    同理:

    int c;
    while( (c = get_me_a_byte_S(file) != SSS ) ....
    

    其中 SSS 可以是 MININT..-129 和 128..MAXINT 中的任何值

    现在,如果您选择第一种方法,则会出现一个问题:UUU(您的 EOF)的值应该是多少?

    (-1) 对 EOF 有好处,因为无论您分配给它的变量的位宽是多少,它都将保持 (-1)。 '保持 -1' 我的意思是它总是全为模式。

    char c = -1; // c = 11111111b / 0xFF / 255 (assuming your char is signed 8bit)
    short s = -1; // s = 1111111111111111b / 0xFFFF / 65535
    int i = -1; // s = 11111111111111111111111111111111b / 0xFFFFFFFF / 4294967295
    

    现在应该很明显了。

    【讨论】:

      【解决方案5】:

      没有矛盾。

      • EOF 不是字符,只是读取文件时发现的条件。
      • ASCII 255 有时对应一个不间断空格,也就是 HTML 实体 &amp;nbsp;

      如 cmets 中所述,ASCII 仅编码 128 个字符,因此除此之外您会发现不同的编码。

      从您链接到的表中,我只想说:

      255 是不可打印的字符

      【讨论】:

      • ASCII 只有 0 .. 127。有几十个字符集以不兼容的方式使用其他字节值,但它们都不是 ASCII(以及术语“扩展 ASCII”中的任何一个它们也具有误导性)。
      猜你喜欢
      • 2018-04-05
      • 1970-01-01
      • 1970-01-01
      • 2012-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多