int和char在getchar / fgetc和putchar / fputc之间的区别?
我想自己学习C,而且我对getchar和putchar感到困惑: 
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指定的字符(unsigned char)写入stdout。 
  C库函数int getchar(void) )从stdin获取一个字符(一个无符号字符)。 这相当于以stdin作为参数的getc。 
 这是否意味着putchar()接受int和char或者其中之一,而getchar()是否应该使用int或char ? 
TL; DR:
-  char c; c = getchar();是错误的,破碎和越野车 。
-  int c; c = getchar();是正确的 。
 这也适用于getc和fgetc ,如果不是更多的话,因为经常会读到文件的末尾。 
 总是将getchar ( fgetc , getc …)(和putchar )的返回值存储到inttypes的variables中。 
  putchar的参数可以是int , char , signed char或unsigned char ; 它的types并不重要,所有这些都是一样的,即使可能导致积极的和其他负面的整数通过以上的字符,包括\200 (128)。 
 您必须使用int来存储getchar和putchar的返回值的原因是,当达到文件结束条件(或发生I / O错误)时,它们都会返回macrosEOF的值是一个负整数常量, (通常是-1 ) 。 
 对于getchar ,如果返回值不是EOF ,则将读取的unsigned char零扩展为int 。 也就是说,假定8位字符,返回的值可以是0 … 255或macrosEOF的值; 再次假定8位字符,没有办法将这257个不同的值压缩到256中,这样每个字符都可以被唯一标识。 
 现在,如果将其存储为char ,则效果将取决于字符types是默认签名还是未签名 ! 这从编译器到编译器,架构到架构都不相同。 如果char被签名并假定EOF被定义为-1 ,则input上的EOF和字符'\377'都将等于EOF ; 他们会被签名扩展到(int)-1 。 
 另一方面,如果char是无符号的(因为在ARM处理器(包括Raspberry PI系统 )中是默认的),所以没有可以存储在c中的值,其将等于-1 ; 包括EOF ; 而不是在EOF ,您的代码将输出一个\377字符。 
  这里的危险是,使用带符号的char代码似乎是正常工作,即使它仍然是可怕的破碎 – 合法的input值之一被解释为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都打印了一个instead,而不是打断循环。 
 现在再次,对于签名的char情况下,它不能区分char 255和EOF在Linux上,打破它的二进制数据等: 
 % gcc test.c && echo -e 'Hello world\0377And some more' | ./a.out Enter characters : Hello world % 
 只有到“ \0377转义的第一部分被写入stdout。 
 请注意,字符常量与包含无符号字符值的int之间的比较可能无法按预期工作(例如,ISO 8859-1中的字符常量'ä'意味着有符号值-28 ,所以假设您编写的代码将读取input直到ISO 8859-1代码页中的'ä' ,你会这样做 
 int c; while((c = getchar()) != EOF){ if (c == (unsigned char)'ä') { /* ... */ } } 
 由于整数提升,所有的char值适合int ,并在函数调用时自动提升,因此你可以给int , char , signed char或unsigned char任何一个以putchar作为参数 (不存储它的返回值),它会按预期工作。 
 以整数传递的实际值可能是正值甚至负值; 例如字符常量\377在8位字符系统上是负的 ,其中char是有符号的; 然而putchar (或者fputc实际上)会将这个值转换为一个无符号的字符。 
 总是使用int来保存getchar()字符,因为EOF常量是inttypes的。 如果使用char那么与EOF的比较是不正确的。 
 你可以安全地将char传递给putchar()因为它会被自动提升为int 。 
  注意 :在大多数情况下,在技术上使用char会起作用,但是不能有0xFF字符,因为types转换将被解释为EOF 。 为了覆盖所有的情况, 总是使用int 。 正如@Ilja所说 – int需要表示所有256个可能的字符值和 EOF ,这是总共257个可能的值,不能以chartypes存储。