繁体   English   中英

getchar/fgetc 和 putchar/fputc 中 int 和 char 的区别?

[英]Difference between int and char in getchar/fgetc and putchar/fputc?

我正在尝试自己学习 C,但我对getcharputchar有点困惑:

1

#include <stdio.h>

int main(void)
{
    char c;
    printf("Enter characters : ");
    while((c = getchar()) != EOF){
      putchar(c);
    }
    return 0;
}

2

#include <stdio.h>

int main(void)
{
    int c;
    printf("Enter characters : ");
    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

特尔;博士:

  • char c; c = getchar(); 错了,坏了,问题
  • int c; c = getchar(); 正确的

这也适用于getcfgetc ,甚至更多,因为人们通常会读取到文件末尾。


始终将getcharfgetcgetc ...)(和putchar )的返回值最初存储到int类型的变量中。

putchar参数可以是intcharsigned charunsigned char 它的类型无关紧要,并且所有这些都相同,即使一个可能导致正整数和其他负整数被传递给上面的字符,包括\\200 (128)。


必须使用int来存储getcharputchar返回值的原因是,当达到文件结束条件时(或发生 I/O 错误),它们都返回宏EOF的值,该值是一个负整数常量, (通常是-1 )

对于getchar ,如果返回值不是EOF ,则它是读取的unsigned char零扩展到int 也就是说,假设是 8 位字符,返回的值可以是0 ... 255或宏EOF的值; 再次假设 8 位字符,无法将这 257 个不同的值压缩到 256 个中,以便可以唯一地识别它们中的每一个。


现在,如果您将其存储到char ,则效果将取决于默认情况下字符类型是有符号还是无符号 这因编译器而异,因架构而异。 如果char被签名并假设EOF定义为-1 ,则两个EOF和字符'\\377'上输入将比较等于EOF ; 它们会被符号扩展到(int)-1

另一方面,如果char是无符号的(默认情况下在 ARM 处理器上是这样,包括Raspberry PI 系统;并且对于AIX似乎也是如此),则没有可以存储在c中的值可以比较等于-1 ; 包括EOF 您的代码将输出一个\\377字符,而不是在EOF上爆发。

这里的危险在于,使用 signed char ,代码似乎可以正常工作,即使它仍然严重损坏 - 合法输入值之一被解释为EOF 此外,C89、C99、C11 不强制要求EOF的值; 它只说EOF是一个负整数常量; 因此,除了-1 ,在特定实现上也可以说-224 ,这会导致空格的行为类似于EOF

gcc具有开关-funsigned-char可用于在默认为有符号的平台上使char无符号:

% cat test.c
#include <stdio.h>

int main(void)
{
    char c;
    printf("Enter characters : ");
    while ((c = getchar()) != EOF){
      putchar(c);
    }
    return 0;
}

现在我们用 signed char运行它:

% gcc test.c && ./a.out
Enter characters : sfdasadfdsaf
sfdasadfdsaf
^D
%

似乎工作正常。 但是使用 unsigned char

% gcc test.c -funsigned-char && ./a.out                   
Enter characters : Hello world
Hello world
���������������������������^C
%

也就是说,我多次尝试在那里按Ctrl-D ,但是每个EOF都打印了一个 而不是打破循环。

现在,再次,对于有符号char情况,它无法区分 Linux 上的char 255 和EOF ,将其分解为二进制数据等:

% gcc test.c && echo -e 'Hello world\0377And some more' | ./a.out 
Enter characters : Hello world
%

只有\\0377转义之前的第一部分被写入标准输出。


请注意,字符常量和包含无符号字符值的int之间的比较可能无法按预期工作(例如,ISO 8859-1 中的字符常量'ä'表示有符号值-28 。因此假设您编写的代码可以读取输入直到 ISO 8859-1 代码页中的'ä' ,你才会这样做

int c;
while ((c = getchar()) != EOF){
    if (c == (unsigned char)'ä') {
        /* ... */
    }
}

由于整数提升,所有char值都适合int ,并在函数调用时自动提升,因此您可以将intcharsigned charunsigned char作为参数提供putchar (不存储其返回值),它会按预期工作。

整数中传递的实际值可能是正数,甚至可能是负数; 例如,字符常量\\377char有符号的 8 位字符系统上将是负数 但是putchar (或实际上是fputc )会将值转换为无符号字符。 C11 7.21.7.3p2

2 fputc 函数将c指定的字符(转换为无符号字符)写入流 [...]

(强调我的)

fputc将保证将给定的c转换为(unsigned char)c

始终使用intgetchar()保存字符,因为EOF常量是int类型。 如果您使用char则与EOF的比较不正确。

您可以安全地将char传递给putchar()因为它会自动提升为int

注意:从技术上讲,在大多数情况下使用char会起作用,但是您不能有 0xFF 字符,因为它们会由于类型转换而被解释为EOF 要涵盖所有情况,请始终使用int 正如@Ilja 所说——需要int来表示所有 256 个可能的字符值EOF ,总共有 257 个可能的值,不能以char类型存储。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM