fgetc 함수의 원형은 다음과 같다.


int fgetc(FILE * fp);


fgetc는 문자 하나를 읽어들이는 함수인데, 왜 int를 반환할까?


char로 반환하면 문제가 생길 수 있기 때문이다.


다음 예를 보자.


char ch;


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

{

//something to do

}


fgetc 함수가 반환하는 값을 char형의 ch 변수에 대입한 후 이 변수와 EOF를 비교하는 반복문이다.


일반적으로는 파일의 끝을 만나기 전까지 while문을 돌 것이라고 예측할 것이다.


이제 여기서 발생할 수 있는 문제점을 살펴보자.


1.


fgetc()가 int를 반환하지만 그 값을 char형 변수에 저장하기 때문에 이 때 int값의 상위 비트들이 잘리게 된다.


이 말은, 16진수 데이터 0x0000FF와, -1을 의미하는 EOF 값 0xFFFFFF 둘 다 모두 0xFF로 잘려진다는 것이다.


따라서 while 루프를 도는 동안 파일의 바이트 FF를 읽어들이고 있는지, 아니면 파일의 마지막을 읽어들이고


있는지를 알 수 없게 된다.


char형으로는 총 256가지 값을 구분할 수 있는데, 우리는 여기에다가 EOF 값(-1)도 구분을 해야 하므로


그렇게 되면 총 257가지 값을 구분해야 되기 때문에 결론적으로 char형의 범위로는 모두 표현할 수 없게 된다.



2.


위 상황의 결과로는 char형이 부호가 있는지(signed) 혹은 부호가 없는지(unsigned)에 따라 2가지로 나뉜다.


왜냐하면, ch가 EOF 값과 비교되는 과정에서, EOF가 int값을 가지고 있으므로 ch의 값이 int로 확장되는데,


데이터가 확장될 때에는 해당 데이터가 signed인지, unsigned 인지에 따라 결과가 달라지기 때문이다.


만약 char형이 unsigned라면 0xFF는 int형으로 확장될 때 0x000000FF로 확장될 것이다.


반면 EOF는 0xFFFFFFFF 이므로 루프에서 절대로 빠져나갈 수 없게 되어 무한루프 상태가 된다.


만약 char형이 signed라면 0xFF는 int형으로 확장될 때 0xFFFFFFFF로 확장될 것이다.


따라서 EOF를 입력받을 때 성공적으로 루프를 빠져 나갈 수 있게 된다.


하지만, 1번에서 보았듯이 0xFF(데이터 값)와 0xFF(EOF 값) 둘 다 0xFFFFFFFF로 확장될 것이기 때문에


파일을 모두 읽어들이지 못한 채 루프를 빠져 나가게 될 수도 있다.



해결방법 :


위 문제를 해결하기 위해서는 ch를 char형이 아닌 int형으로 선언해야 한다.


int형은 0xFFFFFFFF(EOF 값)와 0x000000FF(데이터 값)을 구분할 수 있으므로 문제가 발생하지 않는다.









Posted by huammmm1
,