fputc - fgetc c
Diferencia entre int y char en getchar/fgetc y putchar/fputc? (2)
Siempre use int
para guardar caracteres de getchar()
ya que la constante EOF
es de tipo int
. Si usa char
, la comparación con EOF
no es correcta.
putchar()
embargo, puede pasar de manera segura char
a putchar()
ya que se promocionará a int
automáticamente.
Nota : Técnicamente, usar char
funcionará en la mayoría de los casos, pero luego no se puede tener el carácter 0xFF, ya que se interpretará como EOF
debido a la conversión de tipo. Para cubrir todos los casos, siempre use int
. Como @Ilja lo puso - int
es necesario para representar los 256 valores de caracteres posibles y el EOF
, que son 257 valores posibles en total, que no se pueden almacenar en el tipo de caracteres.
getchar
aprender C por mi cuenta y estoy un poco confundido con getchar
y 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;
}
La función de biblioteca C int putchar(int c)
escribe un carácter (un carácter sin signo) especificado por el argumento char a stdout.
La función de biblioteca C int getchar(void)
obtiene un carácter (un carácter sin signo) de stdin. Esto es equivalente a getc con stdin como argumento.
¿Significa que putchar()
acepta tanto int
como char
o cualquiera de ellos y para getchar()
deberíamos usar un int
o char
?
TL; DR:
-
char c; c = getchar();
está mal, roto y con errores . -
int c; c = getchar();
es correcto
Esto también se aplica a getc
y fgetc
, si no aún más, porque uno leería a menudo hasta el final del archivo.
getchar
siempre el valor de retorno de getchar
( fgetc
, getc
...) (y putchar
) inicialmente en una variable de tipo int
.
El argumento para putchar
puede ser cualquiera de int
, char
, signed char
o unsigned char
; su tipo no importa, y todos funcionan de la misma manera, aunque uno puede dar como resultado números enteros positivos y otros en números enteros negativos que se pasan para los caracteres anteriores e incluyen /200
(128).
La razón por la que debe usar int
para almacenar el valor de retorno de getchar
y putchar
es que cuando se alcanza la condición de fin de archivo (o se produce un error de E / S), ambos devuelven el valor de la macro EOF
que es una constante entera negativa, (generalmente -1
) .
Para getchar
, si el valor de retorno no es EOF
, es el unsigned char
lectura zero-extended a un int
. Es decir, suponiendo caracteres de 8 bits, los valores devueltos pueden ser 0
... 255
o el valor de la macro EOF
; asumiendo de nuevo el carácter de 8 bits, no hay forma de exprimir estos 257 valores distintos en 256 para que cada uno de ellos pueda identificarse de manera única.
Ahora, si lo almacena en char
, el efecto dependerá de si el tipo de carácter está firmado o no de manera predeterminada . Esto varía de compilador a compilador, arquitectura a arquitectura. Si se firma EOF
y suponiendo que EOF
se define como -1
, entonces tanto EOF
como el carácter ''/377''
en la entrada se compararían con EOF
; se extenderán a (int)-1
.
Por otro lado, si char
no está firmado (como lo es de forma predeterminada en los procesadores ARM, incluidos los sistemas Raspberry PI , y parece ser cierto también para AIX ), no hay ningún valor que pueda almacenarse en c
que compare igual a -1
; incluido EOF
; en lugar de irrumpir en EOF
, su código generaría un único /377
caracteres.
El peligro aquí es que con las char
firmadas el código parece estar funcionando correctamente aunque todavía esté terriblemente roto: uno de los valores de entrada legales se interpreta como EOF
. Además, C89, C99, C11 no exige un valor para EOF
; solo dice que EOF
es una constante entera negativa; por lo tanto, en lugar de -1
, podría decirse -224
en una implementación particular, lo que haría que los espacios se comporten como EOF
.
gcc
tiene el -funsigned-char
que se puede usar para hacer que el char
no esté firmado en esas plataformas donde se registra por defecto:
% cat test.c
#include <stdio.h>
int main(void)
{
char c;
printf("Enter characters : ");
while((c= getchar()) != EOF){
putchar(c);
}
return 0;
}
Ahora lo ejecutamos con char
firmado:
% gcc test.c && ./a.out
Enter characters : sfdasadfdsaf
sfdasadfdsaf
^D
%
Parece estar funcionando bien. Pero con char
sin signo:
% gcc test.c -funsigned-char && ./a.out
Enter characters : Hello world
Hello world
���������������������������^C
%
Es decir, intenté presionar Ctrl-D
varias veces, pero se imprimió un for por cada EOF
lugar de romper el ciclo.
Ahora, de nuevo, para el caso char
firmado, no se puede distinguir entre char
255 y EOF
en Linux, rompiéndolo para datos binarios y cosas por el estilo:
% gcc test.c && echo -e ''Hello world/0377And some more'' | ./a.out
Enter characters : Hello world
%
Solo la primera parte hasta el escape /0377
fue escrita en stdout.
Tenga en cuenta que las comparaciones entre las constantes de caracteres y un int
contiene el valor del carácter sin firmar podrían no funcionar como se esperaba (por ejemplo, la constante de carácter ''ä''
en ISO 8859-1 significaría el valor con signo -28
. Por lo tanto, suponiendo que escriba código que leería hasta que ''ä''
en la página de códigos ISO 8859-1, harías
int c;
while((c = getchar()) != EOF){
if (c == (unsigned char)''ä'') {
/* ... */
}
}
Debido a la promoción entera, todos los valores char
encajan en un int
, y se promueven automáticamente en llamadas a función, por lo que puedes dar cualquiera de int
, char
, signed char
o unsigned char
a putchar
como argumento (no para almacenar su valor de retorno), y funcionaría como se esperaba.
El valor real pasado en el entero puede ser positivo o incluso negativo; por ejemplo, la constante de caracteres /377
sería negativa en un sistema de 8 bitchar, donde char
está firmado; sin embargo, putchar
(o fputc
realidad) arrojará el valor a un char sin signo. C11 7.21.7.3p2 :
2 La función fputc escribe el carácter especificado por
c
(convertido a un carácter sin signo) en la secuencia de salida a la que apunta el flujo [...]
(énfasis mío)
Es decir, se garantiza que el fputc
convertirá la c
dada como si fuera (unsigned char)c