Comparando caracteres sin signo y EOF

cuando se comstack el siguiente código, entra en un ciclo infinito:

int main() { unsigned char ch; FILE *fp; fp = fopen("abc","r"); if(fp==NULL) { printf("Unable to Open"); exit(1); } while((ch = fgetc(fp))!=EOF) printf("%c",ch); fclose(fp); printf("\n",ch); return 0; } 

El comstackdor gcc también advierte sobre la comstackción

 abc.c:13:warning: comparison is always true due to limited range of data type 

el código se ejecuta correctamente cuando unsigned char se reemplaza por char o int como se esperaba, es decir, termina.
Pero el código también funciona bien para unsigned int también. como lo he leído en EOF se define como -1 en stdio.h entonces, ¿por qué este código falla para char sin signo pero funciona bien para int sin firmar?

La regla de oro para escribir esta línea es

  while ((ch = fgetc(stdin)) != EOF) 

ch debe ser int Su truco lindo de hacer ch unsigned falla porque EOF es una cantidad int firmada.

Ok, veamos ahora la profundidad ……

Paso 1:

 ch=fgetc(fp) 

fgetc() devuelve -1 (un int firmado). Por las reglas de oro de C ch obtiene el último octeto de bits, que es todo 1 ‘s. Y de ahí el valor 255 . El patrón de byte de ch después de la ejecución de

 ch = fgetc(fp); 

sería así

 11111111 

Paso 2:

 ch != EOF 

Ahora EOF es un entero con signo y ch es un unsigned char

Una vez más, me refiero a la regla de oro de C … el chico más chico ch se convierte en gran tamaño int antes de la comparación, por lo que su patrón de bytes es ahora

 00000000000000000000000011111111 = (255)10 

mientras que EOF es

 11111111111111111111111111111111 = (-1)10 

No hay forma de que puedan ser iguales … De ahí la afirmación de dirigir el siguiente while-loop

 while ((ch = fgetc(stdin)) != EOF) 

nunca evaluará a falso …

Y de ahí el ciclo infinito.

Hay varias conversiones implícitas pasando. No son realmente relevantes para la advertencia específica, pero los incluí en esta respuesta para mostrar lo que el comstackdor realmente hace con esa expresión.

  • ch en su ejemplo es de tipo char sin signo.
  • Se garantiza que EOF es del tipo int (C99 7.19.1).

Entonces la expresión es equivalente a

 (unsigned char)ch != (int)EOF 

Las reglas de promoción de enteros en C convertirán implícitamente el carácter sin signo a unsigned int:

 (unsigned int)ch != (int)EOF 

Entonces las reglas de equilibrio (también conocidas como las conversiones aritméticas habituales ) en C convertirán implícitamente el int a unsigned int, porque cada operando debe tener el mismo tipo:

 (unsigned int)ch != (unsigned int)EOF 

En su comstackdor EOF es probable -1:

 (unsigned int)ch != (unsigned int)-1 

que, suponiendo CPU de 32 bits, es lo mismo que

 (unsigned int)ch != 0xFFFFFFFFu 

Un personaje nunca puede tener un valor tan alto, de ahí la advertencia.

Me he encontrado con este problema también. Mi solución es usar feof ().

 unsigned int xxFunc(){ FILE *fin; unsigned char c; fin = fopen("...", "rb"); if(feof(fin) != 0) return EOF; c = fgetc(fin); fclose(fin); ... } 

Y puede definir una variable int para compararla con EOF. Por ejemplo:

 int flag = xxFunc(); while(flag != EOF) {...} 

Esto funciona para mí

** ACTUALIZACIÓN IMPORTANTE * **

Después de usar el método que mencioné antes, encontré un problema grave. feof () no es una buena manera de romper el ciclo while. Esta es la razón para ello. http://www.gidnetwork.com/b-58.html

Entonces encuentro una mejor manera de hacer esto. Yo uso una variable int para hacerlo. aquí:

 int flag; unsigned char c; while((flag = fgetc(fin)) != EOF) { //so, you are using flag to receive, but transfer the value to c later. c = flag; ... } 

Después de mi prueba, esto funciona.

necesitas usar un int

fgetc () devuelve un int específicamente para que pueda indicar el final del archivo

funciona bien con el carácter firmado porque EOF (-1) está en el rango, pero se rompería si lee un carácter con un valor superior a 127.

Usa un int, ponlo en un char después de que hayas marcado EOF

Cuando compara una int sin firmar con una int firmada, convierte la int firmada en unsigned int y las compara. Por lo tanto, cuando está leyendo el archivo con un int ‘ch’ sin signo, leer un EOF le da 2 ^ 32 + 1 (en una máquina int de 4 bytes) y al compararlo con EOF, convierte EOF en unsigned, que también es 2 ^ 32 + 1 y por lo tanto el progtwig se detiene!

Si usa caracteres sin signo, cuando lee el archivo, leer EOF devuelve 2 ^ 32 + 1, y esto se convertirá en char sin signo, que trunca el valor en los primeros 8 bits (en una máquina de caracteres de 1 byte) y le da una salida de 255. Por lo tanto, está comparando 255 y 2 ^ 32 + 1, lo que causa un bucle infinito.

El problema aquí es truncar antes de comparar.

Si utiliza

 while((ch = fgetc(fp))!=(unsigned char)EOF) printf("%c",ch); 

¡tu progtwig correrá bien!

se produce una advertencia de pelusa con este tipo de implementación

Comparando el tipo ‘char’ con EOF

  // read the data in a buffer 611 ch = getc(csv_file); 612 while (ch != EOF) 

FIJAR:

 // read the data in a buffer while ((ch = getc(csv_file)) != EOF)