¿Diferencia entre int y char en getchar/fgetc y putchar/fputc?

Resuelto ragmha asked hace 8 años • 2 respuestas

Estoy intentando aprender C por mi cuenta y estoy un poco confundido con getchary 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 la biblioteca C int putchar(int c)escribe un carácter (un carácter sin firmar) especificado por el argumento char en la salida estándar.

La función de la biblioteca C int getchar(void)obtiene un carácter (un carácter sin firmar) de la entrada estándar. Esto es equivalente a getc con stdin como argumento.

¿Significa que putchar()acepta ambos inty charo cualquiera de ellos y para getchar()deberíamos usar un into char?

ragmha avatar Feb 12 '16 13:02 ragmha
Aceptado

TL;DR:

  • char c; c = getchar();está mal, roto y con errores .
  • int c; c = getchar();es correcto .

Esto se aplica getctambién fgetc, si no más, porque a menudo uno leería hasta el final del archivo.


Almacene siempre el valor de retorno de getchar( fgetc, getc...) (y putchar) inicialmente en una variable de tipo int.

El argumento puede putcharser cualquiera de int, charo signed char; unsigned charsu tipo no importa, y todos funcionan igual, aunque uno podría dar como resultado que se pasen enteros positivos y otros negativos para los caracteres superiores e incluidos \200(128).


La razón por la que debes usar intpara almacenar el valor de retorno de ambos getchares putcharque 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, EOFque es un entero negativo. constante, (normalmente -1) .

Porque getchar, si el valor de retorno no es EOF, es la lectura unsigned charextendida a cero a un int. Es decir, asumiendo caracteres de 8 bits, los valores devueltos pueden ser 0... 255o el valor de la macro EOF; Suponiendo nuevamente un carácter de 8 bits, no hay forma de comprimir estos 257 valores distintos en 256 para que cada uno de ellos pueda identificarse de forma única.


Ahora, si lo almacenara en charsu lugar, el efecto dependería de si el tipo de carácter está firmado o sin firmar de forma predeterminada . Esto varía de un compilador a otro, de una arquitectura a otra. Si charestá firmado y suponiendo EOFque se define como -1, entonces tanto EOF el carácter como '\377'el de la entrada se compararían igual a EOF; se extenderían con signos a (int)-1.

Por otro lado, si charno está firmado (como lo está 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 cque se compare igual a -1; incluido EOF; en lugar de dividirse en EOF, su código generaría un solo \377carácter.

El peligro aquí es que con los signos firmados charel código parece funcionar 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; sólo dice que EOFes una constante entera negativa; por lo tanto, en lugar de -1eso, también podría decirse -224sobre una implementación particular, lo que haría que los espacios se comportaran como EOF.

gcctiene el interruptor -funsigned-charque se puede usar para hacer que charno esté firmado en aquellas plataformas donde está firmado de forma predeterminada:

% 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 firmado char:

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

Parece estar funcionando bien. Pero con sin firmar char:

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

Es decir, intenté presionar Ctrl-Dallí muchas veces pero se imprimió un para cada una EOFen lugar de romper el bucle.

Ahora, nuevamente, para el charcaso firmado, no puede distinguir entre char255 y EOFen Linux, dividiéndolo en datos binarios y demás:

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

Sólo la primera parte hasta el \0377escape se escribió en la salida estándar.


Tenga en cuenta que las comparaciones entre constantes de caracteres y un intvalor que contiene el carácter sin firmar podrían no funcionar como se esperaba (por ejemplo, la constante de caracteres 'ä'en ISO 8859-1 significaría el valor con signo -28. Entonces, suponiendo que escriba código que lea la entrada hasta 'ä'ISO 8859-1 página de códigos, lo harías

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

Debido a la promoción de enteros, todos charlos valores caben en , y se promocionan automáticamente en las llamadas aint funciones, por lo que puede dar cualquiera de int, charo signed charto unsigned charcomo putcharargumento (no para almacenar su valor de retorno) y funcionaría como se esperaba.

El valor real pasado en el número entero puede ser positivo o incluso negativo; por ejemplo, la constante de caracteres \377sería negativa en un sistema de caracteres de 8 bits donde charestá firmado; sin embargo putchar(o fputcen realidad) convertirá el valor a un carácter sin firmar. 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 el flujo de salida al que apunta el flujo [...]

(el énfasis es mío)

Es decir, se fputcgarantizará que convertirá lo dado ccomo si fuera por(unsigned char)c

Úselo siempre intpara guardar el carácter ya getchar()que la EOFconstante es de inttipo. Si lo usa char, la comparación EOFno es correcta.

Sin embargo , puedes pasar chara él con seguridad putchar(), ya que se promocionará intautomáticamente.

Nota : Técnicamente, el uso charfuncionará en la mayoría de los casos, pero no puede tener el carácter 0xFF, ya que se interpretará como EOFuna conversión de tipo. Para cubrir todos los casos utilice siempreint . Como lo expresó @Ilja, intes necesario representar los 256 valores de caracteres posibles y , que EOFson 257 valores posibles en total, que no se pueden almacenar en chartipo.

JohnLM avatar Feb 12 '2016 06:02 JohnLM