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 a compilation warning

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

the code works fine when an unsigned char is replaced with a char or int , as expected, i.e. it ends.
But the code is also great for unsigned int . as I read in EOF , it is defined as -1 in stdio.h , then why this code fails for unsigned char, but works fine for unsigned int.

+7
source share
6 answers

The golden rule for writing this line

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

ch must be int . Your cute trick to making ch unsigned failed is because EOF is the signed amount of int.

Ok, now we go into the depths ...

Step 1:

 ch=fgetc(fp) 

fgetc() returns -1 (signed int ). By golden rules, C ch receives the last octet of a bit, which is all 1 . And therefore, the value is 255 . Ch byte pattern after execution

 ch = fgetc(fp); 

will be that way

 11111111 

Step 2:

 ch != EOF 

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

Again I refer to the golden rule C ... the smaller guy ch converted to a large int size before comparison, so his byte pattern is now

 00000000000000000000000011111111 = (255)10 

and EOF -

 11111111111111111111111111111111 = (-1)10 

There is no way that they can be equal ....... Therefore, an instruction to control the next while-loop

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

will never evaluate to false ...

And therefore, an endless cycle.

+8
source

Several implicit conversions occur. They have nothing to do with a specific warning, but I included them in this answer to show what the compiler really does with this expression.

  • ch in your example is of type unsigned char.
  • EOF is guaranteed to be of type int (C99 7.19.1).

So the expression is equivalent

 (unsigned char)ch != (int)EOF 

Integer promotion rules in C will implicitly convert unsigned char to unsigned int:

 (unsigned int)ch != (int)EOF 

Then the balancing rules (the so-called ordinary arithmetic conversions) in C will implicitly convert int to unsigned int, because each operand must have the same type:

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

In your EOF compiler, most likely -1:

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

which, assuming a 32-bit CPU, matches the

 (unsigned int)ch != 0xFFFFFFFFu 

A symbol can never have such a high value, so a warning.

+7
source

you need to use int

fgetc () returns int specifically to indicate the end of the file

it works fine with signed char because EOF (-1) is in range, but it breaks if you read in char with value greater than 127.

Use int, pass it char after you checked EOF

+2
source

I also ran into this problem. My solution is to use feof ().

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

And you can define an int variable for comparison with EOF. For instance:

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

This works for me.

** IMPORTANT UPDATE ***

After using the method that I mentioned earlier, I found a serious problem. feof () is not a good way to break a while loop. That's why. http://www.gidnetwork.com/b-58.html

So, I find the best way to do this. For this, I use the int variable. here:

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

After my test, it works.

+2
source

When you compare an unsigned int with a signed int, it converts the signed int to unsigned int and compares them. Therefore, when you read a file with unsigned int 'ch', reading EOF gives you 2 ^ 32 + 1 (on a 4-byte int machine), and when compared to EOF, it converts EOF to unsigned, which is also 2 ^ 32 + 1 and therefore the program stops!

If you use unsigned char ch when you read the file, reading EOF returns 2 ^ 32 + 1, and this will be passed to unsigned char, which truncates the value to the first 8 bits (1 char byte) and gives you a result of 255. Therefore, you compare 255 and 2 ^ 32 + 1, causing an infinite loop.

The problem is truncation before comparison.

If you use

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

the program will work fine!

0
source

lint warning appears with such an implementation

Comparing char with EOF

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

FIX:

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

Source: https://habr.com/ru/post/904220/


All Articles