在 getchar/fgetc 和 putchar/fputc 函数中,int 和 char 之间的区别是什么?

13 浏览
0 Comments

在 getchar/fgetc 和 putchar/fputc 函数中,int 和 char 之间的区别是什么?

我正在尝试自学C语言,对于getcharputchar有些困惑:

1

#include 
int main(void)
{
    char c;
    printf("输入字符:");
    while((c = getchar()) != EOF){
      putchar(c);
    }
    return 0;
}

2

#include 
int main(void)
{
    int c;
    printf("输入字符:");
    while((c = getchar()) != EOF){
      putchar(c);
    }
    return 0;
}

C库函数int putchar(int c)将参数char指定的字符(无符号字符)写入标准输出stdout。

C库函数int getchar(void)从标准输入stdin获取一个字符(无符号字符)。这等同于使用stdin作为参数的getc函数。

这是否意味着putchar()接受intchar两者之一或者两者都可以,而对于getchar()我们应该使用int或者char

0
0 Comments

在使用getchar/fgetc和putchar/fputc函数时,使用int类型的变量来存储返回值是正确的做法,而使用char类型的变量则是错误的。这一点同样适用于getc和fgetc函数,因为在读取文件直到文件末尾的情况下,更容易出现错误。

使用int类型来存储getchar/fgetc和putchar/fputc函数的返回值的原因是,当达到文件末尾条件(或发生I/O错误)时,它们都会返回宏EOF的值,这是一个负整数常量(通常为-1)。对于getchar函数来说,如果返回值不是EOF,那么它就是读取的无符号字符,然后将其零扩展为int类型。换句话说,假设字符占8位,返回的值可以是0...255或宏EOF的值,而不能将这257个不同的值压缩到256个中,以便每个值都可以唯一地标识。

如果将返回值存储在char类型的变量中,效果将取决于字符类型是默认为有符号还是无符号的。这取决于编译器和架构。如果char是有符号的,并且假设EOF被定义为-1,那么EOF和字符'\377'在输入时都将与EOF相等;它们会被符号扩展为(int)-1。另一方面,如果char是无符号的(如在ARM处理器上,默认情况下是无符号的;似乎对于AIX也是如此),那么就没有任何值可以存储在char中与-1相等;包括EOF。因此,在遇到EOF时,代码将输出一个单独的\377字符。有问题的是,对于有符号的char,代码似乎运行正常,即使它仍然是错误的——其中一个合法的输入值被解释为EOF。此外,C89、C99和C11并未规定EOF的值;它只说EOF是一个负整数常量;因此,EOF的值也可能是-224,这会导致空格的行为类似于EOF。

为了解决这个问题,可以使用gcc的-funsigned-char选项将char类型转换为无符号的。这样,就可以正确处理EOF。

与字符常量进行比较时,使用int类型来存储无符号字符值的变量可能无法按预期工作。例如,ISO 8859-1编码中的字符常量'ä'表示有符号值-28。因此,如果编写的代码在ISO 8859-1代码页中读取输入直到'ä',可以这样做:

int c;

while ((c = getchar()) != EOF){

if (c == (unsigned char)'ä') {

/* ... */

}

}

由于整数提升,所有char值都适合int类型,并且在函数调用时会自动提升。因此,可以将int、char、signed char或unsigned char类型的任何值传递给putchar作为参数,并且它们的工作方式都相同。

由于fputc函数将参数c转换为无符号字符,所以传递给它的整数实际上可能是正数甚至负数。例如,字符常量\377在使用8位char和有符号char的8位字符系统上将是负数;然而,fputc会将该值转换为无符号字符。因此,fputc保证将给定的c转换为(unsigned char)c。

总之,使用int类型来存储getchar/fgetc和putchar/fputc函数的返回值是正确的,因为它们可以区分EOF和普通字符。使用char类型则会导致将某个合法字符值误认为是EOF。在某些特殊情况下,比如土耳其语使用字母ÿ(y-umlaut,U+00FF,LATIN SMALL LETTER Y WITH DIAERESIS),将getchar()的返回值直接存储到有符号char类型中会被错误地识别为EOF。这个问题几乎和永远不将任何值识别为EOF一样严重。

标准规定了对于fgetc(getchar是以getc(stdin)实现的,getc等效于fgetc)的行为,即如果输入流的文件结束标志未设置并且存在下一个字符,则fgetc函数将该字符作为无符号字符转换为int类型。如果输入流的文件结束标志已设置,或者输入流已经到达文件结尾,则fgetc函数返回EOF。

如果直接将getchar()的返回值存储在有符号char类型的变量中,就会出现一个合法字符值被误认为是EOF的问题。这个问题几乎和永远不将任何值识别为EOF一样严重。

这些解释和示例可以帮助我们理解为什么使用int而不是char来存储getchar/fgetc和putchar/fputc函数的返回值,以及这样做的原因和解决方法。

0
0 Comments

在使用getchar和fgetc函数时,始终使用int类型来保存字符,因为EOF常量是int类型的。如果使用char类型,与EOF进行比较是不正确的。然而,可以安全地将char类型传递给putchar和fputc函数,因为它们会自动转换为int类型。

虽然从技术上讲,大多数情况下使用char类型也可以工作,但是如果使用char类型,就无法使用0xFF字符,因为它们会被解释为EOF。为了涵盖所有情况,始终使用int类型。因为int类型需要表示所有256个可能的字符值和EOF,总共是257个可能的值,而char类型无法存储这么多值。

EOF是(int)-1,对于char类型来说超出了范围。有符号的char类型范围是-128到127。在32位机器上,(int)-1是0xFFFFFFFF,对于char类型来说超出了范围,但是(signed char)-1仍然在比较过程中被提升为int类型。这就是为什么它通常可以工作的原因,但如果不使用int来存储字符,就无法将0xFF作为有效字符保存。也就是说,使用int来存储它将被保存为0x000000FF,这与EOF不同。

使用char类型通常可以工作是错误的,标准并没有规定char类型是有符号的。它在大多数情况下可以工作,但我不是说这样是安全的。

因此,如果希望在流中使用0xFF,或者不知道char类型是有符号还是无符号,建议始终使用int类型。当然,EOF也可能被定义为除了-1之外的其他值。

所以,你是在告诉我最好读取一个char值并将其存储在int变量中吗?你只需要使用signed char如果需要的话。你仍然没有在自己的答案中证明你的观点,我多次要求你这样做,以便理解我的错误。我得出的结论是:你更喜欢用错误的观点来捍卫你的编程习惯。

是的!至少在与EOF进行比较之前是这样。之后,你可以将其存储为char。但我也在说,getchar返回的是int,有其原因。

我同意它返回int。我试图理解你们在谈论什么问题,但我决定放弃了。我无法理解,我想。我知道比较char和int从来没有任何问题,因为存在隐式转换(就像比较int和float一样)。

我建议你努力理解这个概念。否则,你的C程序将会有很多错误。

(int)-1在有符号char范围内。C使用值语义。问题是,当两者都被分配给相同类型的变量时,无法区分(int)-1和(char)-1。

接受的回答给出了一个很好的解释:假设8位的char类型,你试图用一个只能表示256个符号的类型来表示257个符号。你需要256个字符+EOF。int类型可以表示它们。

我不明白,256个字符+EOF?你是指256个符号吗?我仍然无法理解,因为EOF是(int)-1。但我感谢你的评论,我会再次阅读整个答案。谢谢!

我现在明白了。再次感谢你。

0