Almacenar el carácter EOF (fin de archivo) en un tipo char
On febrero 18, 2021 by admin Leí en el lenguaje de programación C de Dennis Ritchie libro que int
debe usarse para que una variable contenga EOF – para que sea lo suficientemente grande como para que pueda contener el valor EOF – no char
. Pero el siguiente código funciona bien:
#include<stdio.h> main() { char c; c=getchar(); while(c!=EOF) { putchar(c); c=getchar(); } }
Cuando hay ya no es una entrada, getchar
devuelve EOF. Y en el programa anterior, la variable c
, con tipo char, es capaz de contenerlo correctamente.
¿Por qué funciona esto? Según la explicación en el libro mencionado anteriormente, el código no debería funcionar.
Comentarios
Respuesta
Su código parece funcionar, porque las conversiones de tipo implícitas accidentalmente hacen lo correcto.
getchar()
devuelve un int
con un valor que se ajusta al rango de unsigned char
o es EOF
( que debe ser negativo, normalmente es -1). Tenga en cuenta que EOF
en sí mismo no es un carácter, sino una señal de que no hay más caracteres disponibles.
Al almacenar el resultado de getchar()
en c
, hay dos posibilidades. O el tipo char
puede representar el valor, en cuyo caso ese es el valor de c
. O el tipo char
no puede representar el valor. En ese caso, no está definido qué sucederá. Los procesadores Intel simplemente eliminan los bits altos que no encajan en el nuevo tipo (reduciendo efectivamente el valor módulo 256 para char
), pero no debe confiar en eso.
El siguiente paso es comparar c
con EOF
. Como EOF
un int
, c
también se convertirá en un int
, conservando el valor almacenado en c
. Si c
pudiera almacenar el valor de EOF
, la comparación se realizará correctamente , pero si c
pudo no almacenar el valor, entonces la comparación fallará, porque ha habido una pérdida irrecuperable de información al convertir EOF
para escribir char
.
Parece que su compilador eligió hacer el tipo char
firmado y el valor de EOF
pequeño suficiente para caber en char
. Si char
no estuviera firmado (o si hubiera usado unsigned char
), su prueba habría fallado, porque unsigned char
«no puede contener el valor de EOF
.
También tenga en cuenta que hay un segundo problema con su código. Como EOF
no es un carácter en sí mismo, pero lo fuerza a un tipo char
, es muy probable que haya un carácter que se malinterpreta como EOF
y para la mitad de los caracteres posibles no está definido si se procesarán correctamente.
Comentarios
- Coacción para escribir
char
valores fuera del rangoCHAR_MIN
..CHAR_MAX
will es necesario para ceder un valor definido por la implementación, producir un patrón de bits que la implementación define como una representación de trampa, o generar una señal definida por la implementación. En la mayoría de los casos, las implementaciones tendrían que realizar mucho trabajo adicional para hacer algo más que dos ' reducción de complemento s.Si la gente del Comité de Estándares se suscribiera a la idea de que se debería alentar a los compiladores a implementar comportamientos consistentes con los de la mayoría de los demás compiladores en ausencia de razones para hacer lo contrario … - … coerción como confiable (por no decir que el código no debe ' t documentar sus intenciones, pero que
(signed char)x
debe considerarse más claro y tan seguro como((unsigned char)x ^ CHAR_MAX+1))-(CHAR_MAX+1)
.) Tal como están las cosas, no ' veo ninguna probabilidad de que los compiladores implementen cualquier otro comportamiento que cumpla con el ' s estándar; el único peligro sería que se pudiera cambiar el Estándar para romper el comportamiento en el supuesto interés de la " optimización ". - @supercat: El estándar está escrito de manera que ningún compilador tenga que producir código que tenga un comportamiento que no sea compatible de forma natural con el procesador al que se dirige. La mayor parte del comportamiento indefinido está ahí porque (en el momento de redactar el estándar) no todos los procesadores se comportan de forma coherente. Con los compiladores cada vez más maduros, los escritores de compiladores han comenzado a aprovechar el comportamiento indefinido para hacer optimizaciones más agresivas.
- Históricamente, la intención del Estándar era principalmente la que usted describe, aunque el Estándar describe algunos comportamientos en detalles suficientes como para requerir que los compiladores de algunas plataformas comunes generen más código del que se requeriría con una especificación más flexible. La coerción de tipo en
int i=129; signed char c=i;
es uno de esos comportamientos. Relativamente pocos procesadores tienen una instrucción que haríac
igual ai
cuando ' s en el rango de -127 a +127 y produciría cualquier mapeo consistente de otros valores dei
a valores en el rango de -128 a +127 que difieran de dos ' reducción del complemento-s, o … - … generaría una señal de manera consistente en tales casos. Dado que el Estándar requiere que las implementaciones produzcan un mapeo consistente o generen una señal de manera consistente, las únicas plataformas donde el Estándar dejaría espacio para algo más que dos ' reducción de complemento s serían cosas como los DSP con hardware aritmético de saturación. En cuanto a la base histórica del comportamiento indefinido, diría que el problema no es ' t solo con las plataformas de hardware. Incluso en una plataforma donde el desbordamiento se comportaría de manera muy consistente, puede ser útil tener un compilador que lo atrape …
0xff
. Almacenando el resultado degetchar()
en unint
resuelve ese problema. Su pregunta es esencialmente la misma que la pregunta 12.1 en las comp.lang.c FAQ , que es un recurso excelente. (Además,main()
debe serint main(void)
y no ' estaría de más agregar unreturn 0;
antes del cierre}
).