컴퓨터공부/C & C++ & STL

Cfaq 16

achivenKakao 2009. 4. 23. 01:24

Q 12.1 이 코드에서 잘못된 부분이 있나요?
char c;
while ((c = getchar()) != EOF) ...
Answer 일단, getchar의 리턴 값을 저장하는 변수는 반드시 int이어야 합니다.
getchar()는 어떠한 문자 값이나, EOF를 리턴할 수 있습니다. EOF는
int 타입이기 때문에 이 리턴 값을 char에 저장하는 것은 EOF를 잘못 해
석하게 할 소지가 있습니다 (특히 char의 타입이 unsigned인 경우 문제가
심각합니다).
위의 코드처럼 getchar()의 리턴값을 char에 담을 경우, 두 가지 결과를
예상할 수 있습니다.
² char의 타입이 signed인 경우, 그리고 EOF가 -1로 정의된 경우, 문자
값이 부호 확장(sign extension)되어, 문자값 255가 (C 언어 표현으
로 '\377' 또는 '\xff') EOF와 같아집니다. 따라서 입력 도중에 입
력 처리가 끝나버릴 수 있습니다.
² char의 타입이 unsigned인 경우, EOF 값이 (상위 비트들이 잘라져
대개 255나 0xff의 값으로) 잘라져서, EOF로 인식이 되지 않아 버
립니다. 따라서 이 경우, 무한 루프에 빠져 버립니다.3
이 버그는 char가 signed이고, 입력이 모두 7 비트 문자인 경우, 발견하기
가 매우 힘듭니다 (char가 signed인지 unsigned인지는 implementationdefined입니다.)


Q 12.2 이 코드는 마지막 문장을 두번 복사하는데 왜 그럴까요?
while (!feof(infp)) {
fgets(buf, MAXLINE, infp);
fputs(buf, outfp);
}
Answer C 언어에서 end-of-file은 단지 입력 루틴이 읽으려 했으나 실패했다는 것
을 의미합니다. (다시 말해 C의 I/O는 Pascal과는 다릅니다.) 일반적으로
다음과 같이 입력 루틴의 리턴 값을 검사해야 합니다:
while (fgets(buf, MAXLINE, infp) != NULL)
fputs(buf, outfp);
대개 feof()를 직접 쓸 이유는 없습니다 ( stdio 함수가 EOF나 NULL을 리
턴한 경우, feof()나 ferror()를 써서 정말로 파일의 끝인지, 읽기(read)
에러인지 검사할 필요가 있긴 합니다.)

Note 예를 들어 fread()나 fwrite(), fgets(), fputs()와 같은 함수들은 에러
가 발생하거나 파일 끝에 다다랐을 때, EOF를 리턴합니다. 이런 함수들이
정말 파일 끝에 다다랐는지 확인할려면 feof()나 ferror()를 써야 하는
것입니다.
이런 경우를 제외하고, feof()를 직접 쓰는 경우는 매우 드뭅니다. 따라서
일반적으로 다음과 같은 코드보다:
while (!feof(fp))
fgets(line, max, fp);
다음과 같은 코드를 쓰기 바랍니다:
while (fgets(line, max, fp) != NULL)
...;
즉, feof()는, end-of-file인지 아닌지 검사하기 위해 쓰는 함수가 아니라,
end-of-file과 error인 상황을 구별하기 위해 쓰는 함수라고 기억하는 것이
좋습니다. (물론 이 목적으로, ferror()를 대신 쓸 수 있습니다.)


Q 12.4 제 프로그램의 프롬프트와 중간 단계까지의 출력은 (특히 파이프를 써서 출
력을 다른 프로그램에 넘길 때), 때때로 스크린에 출력되지 않습니다.
Answer 출력이 당장 스크린에 반영되기를 원한다면4 (특히 텍스트가 \n으로 끝나
지 않는 경우), fflush(stdout)을 불러 주는 것이 좋습니다. 대개의 메커
니즘이 적절한 시기에 자동으로 fflush()를 불러주지만, 이 메커니즘들은
stdout이 interactive한 터미널로 연결되어 있다고 가정한 것이기 때문에,
가끔 제대로 동작하지 않을 수 있습니다. (덧붙여 질문 12.24도 참고하시기
바랍니다.)