C라이브러리 함수를 작성하면서 예전에 궁금했던 기억이 나서 글을 자성하게 되었습니다.

혹시 이런 궁금증이 없으셨는지요? 파일을 처리하는 함수를 보면 FILE 구조체를 사용하는 fopen() 계열이 있고 파일 디스크립터를 이용하는 open() 함수 계열이 있습니다. fopen()으로 열기를 하면 fclose()를 이용하여 파일을 닫아야 하고 open()으로 열기를 했다면 close()로 파일을 닫아야 합니다. 같은 작업을 하는 함수를 왜 2개씩 따로 두었을까요?

어떤 책에서는 fopen() 쪽을 표준 함수 또는 고급 함수라고 하고 open()쪽의 함수를 저수준 함수 또는 시스템 제공 함수라고도 합니다. 고급과 저급으로 나누는 이유는 아무래도 open()함수 쪽 보다는 fopen()쪽이 더 편리하고 다양한 함수를 제공하기 때문이겠습니다만, 실제로 fopen() 쪽의 함수가 C 표준 라이브러리 함수라면 open()함수 쪽은 유닉스가 제공하는 함수로 시스템에 근접하기 때문이라 생각됩니다.

즉, 유닉스가 제공하는 함수를 이용하여 프로그래머거 더욱 편리하게 작업할 수 있도록 C 라이브러리 함수로 다시 편리하게 작성한 것이 fopen() 함수입니다.

파일 디스크립터와 파일 스트림

겉으로의 차이점은 open() 함수는 사용하는 파일을 구별하기 위해 파일 디스크립터라는 정수 번호로 지정하여 사용하는 반면 fopen()함수는 FILE 구조체 정보, 즉 파일 스트림 정보를 구합니다. 즉, 정수값만 구하는 open()함수 보다도 fopen()은 FILE 의 다양한 정보를 구하게 되는데 이것만 보더라도 open()계열 함수 보다 더 다양한 함수와 편리함을 제공합니다.

파일 디스크립터 파일 스트림

open()
close()
create()
read()
write()
lseek()
fcntl()

fopen()
fclose()
fgetc()
fputc()
fgets()
fputs()
fscanf()
fprintf()
fread()
fwrite()
ungetc()
feof()
ferror()
clearerr()
ftell()
rewind()
fseek()

그렇다고 open() 쪽의 함수가 필요없다는 것은 아닙니다. 시스템에 가까운 만큼 파일 이외에 장치를 사용하는 곳에서는 오히려 open()쪽의 함수가 더 편리할 수 있습니다.

이식성

이 외에도 C 표준 라이브러리를 사용하는 것이 이식성이 좋다는 것으로 알고 있습니다. 말 그대로 표준 라이브러리이니까요.

직접 경험한 적은 없습니다만 비슷하게 보이는 유닉스 프로그램과 리눅스 프로그램도 시스템에 종속된 함수를 이용하면 소스를 그 시스템에 맞추어 다시 수정해 주어야하고, 때로는 매우 까다로운 경우도 있다고 하더군요. 대신에 C 표준 라이브러리만을 사용하면 이러한 변경작업이 매우 수월하다고 합니다.

대부분의 C 컴파일러는 표준을 준수하려고 합니다. 예로 아주 예전에 MS DOS 시절에 Turbo-C 에서는 fopen()과 함께 open()함수도 있어습니다. 그러나 MS Windows의 Visual C에서는 fopen()은 있는데, open() 함수는 없고 대신에 _open() 함수가 있는 것으로 알고 있습니다. 그러므로 가급적 표준 함수를 사용하는 것이 좋습니다.

이중 버퍼

fopen() 쪽의 함수는 C 표준 라이브러리에서 잡아주는 버퍼를 이용하며, open() 함수는 시스템에서 제공해 주는 버퍼를 이용합니다. 그러므로 C 표준 라이브러리인 fopen() 함수를 사용하게 되면 C 표준 라이브러리가 제공하는 버퍼와 함께 시스템에서 제공해 주는 버퍼를 사용하게 되어 실제 처리에서 버퍼를 이중으로 사용하게 됩니다.

시스템 버퍼가 있음에도 다시 C 라이브러리에서 버퍼를 제공하는 이유는 효율성을 높이기 위해서 입니다. 즉, 시스템 버퍼는 장치를 사용하기 위한 버퍼이므로 사정에 따라서는 버퍼에 있는 자료를 버려야하는 경우가 생길 수 있습니다.

그러나 C 라이브러리에서는 이런 문제점을 피하기 위해 버퍼를 하나 더 두고 시스템의 버퍼의 상태에 맞추어 입출력이 되도록 함으로서 프로그램 성능을 향상 시키고 안정성을 높여 줍니다.

 

태그: *C언어