Search code examples
ccomparisoneofunsigned-charfgetc

Comparing unsigned char and EOF


when the following code is compiled it goes into an infinite loop:

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;
}

The gcc Compiler also gives warning on compilation

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

the code runs fine when unsigned char is replaced by char or int as expected i.e. it terminates.
But the code also runs fine for unsigned int as well. as i have i have read in EOF is defines as -1 in stdio.h then why does this code fails for unsigned char but runs fine for unsigned int.


Solution

  • The golden rule for writing this line is

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

    ch should be int .Your cute trick of making ch unsigned fails because EOF is a signed int quantity.

    Ok, let's now go into the depth......

    Step 1:

    ch=fgetc(fp)
    

    fgetc() returns -1 (a signed int). By the golden rules of C ch gets the last octet of bits which is all 1's. And hence the value 255. The byte pattern of ch after the execution of

    ch = fgetc(fp); 
    

    would thus be

    11111111
    

    Step 2:

    ch != EOF
    

    Now EOF is a signed integer and ch is an unsigned char ...

    Again I refer to the golden rule of C ... the smaller guy ch is converted to big size int before comparision so its byte pattern is now

    00000000000000000000000011111111 = (255)10
    

    while EOF is

    11111111111111111111111111111111 = (-1)10
    

    There is no way they can be equal....... Hence the statement to steer the following while-loop

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

    will never evaluate to false ...

    And hence the infinite loop .