사전 지식
파일 디스크립터 (FD)
- 운영체제가 파일 또는 하드웨어와 통신을 하기 위해 부여하는 숫자라고 한다.
- 파일 디스크립터는 0,1,2 순으로 숫자를 부여하며, 0,1,2는 이미 사용중이어서 3부터 파일 디스크립터를 부여한다.
0 : 표준 입력
1 : 표준 출력
2 : 표준 에러
open()
- 파일을 열고 파일 디스크립터 값을 반환한다. 그 값을 이용하여 이후에도 계속해서 그 열었던 파일에 접근할 수 있다고 한다.
read() 함수
size_t read(int fd, void *buf, size_t bytes)
- 인자로 받은 bytes의 수 만큼 fd를 읽어 buf에 저장하는 함수다.
- 읽어 온 바이트 수를 반환하며, 실패시 -1을 반환한다.
- 파일을 끝까지 읽었다면, 다음 번에는 더 이상 읽을 바이트가 없기 때문에 0을 반환한다.
정적 변수 (Static Var)
- 변수를 선언할 때 static 키워드를 붙여 선언한다. static int num
- 메모리의 데이터 영역에 저장되어 프로그램이 종료될 때까지 남아있는 변수다.
- 함수를 벗어나도 해당 변수는 사라지지 않고 계속 유지된다. 하지만 함수 내부에서 선언되었다면, 다른 함수에서는 이 값을 참조할 수 없다. 또한 함수의 시작이 아닌 프로그램의 시작 시 할당이 되며, 프로그램이 종료될 때 해제된다.
- 함수 내에서 static int num = 0 식으로 초기화하면 프로그램이 시작될 때 변수를 초기화하며, 함수가 호출될 때는 변수를 초기화하지 않는다. (여러 번 함수를 실행하더라도 그 변수가 또 초기화되지 않는다)
- 정적 변수는 초깃값을 지정하지 않으면 0으로 알아서 초기화된다.
- 이번 과제에서는, 다음 line을 읽을 시작 주소를 계속 저장할 수 있도록 백업 버퍼를 만들어 static 변수로 선언해야 한다.
gcc의 -d 플래그
- 프로그램 외부에서 #define을 정의하여 컴파일 시 반영할 수 있다.
- 이 과제에서, 채점 시 컴파일은 다음과 같이 진행한다.
$ gcc -Wall -Wextra -Werror -D BUFFER_SIZE=32 get_next_line.c get_next_line_utils.c
- 즉 컴파일할 때 BUFFER_SIZE를 정하고 이 버퍼의 크기만큼 파일을 한 번에 읽게 된다.
과제의 목표
- GNL 함수를 반복문 안에서 호출하면, fd의 텍스트를 EOF가 올 때까지 한 번에 한 줄씩 읽을 수 있다.
- GNL 함수를 처음 호출했을 때 지정한 버퍼의 크기가 매우 커서 한 번에 파일을 끝까지 읽었다 하더라도, 두 번째 호출했을 때는 두번째 줄부터 읽기를 시작해야 한다.
- file, redirection, stdin 으로부터 읽었을 때 함수가 제대로 작동해야 한다.
- gcc -d 플래그로 받은 BUFFER_SIZE가 1일 때도, 9999일 때도, 10000000일 때도 함수가 제대로 작동해야 한다.
작동 구조 고민
- 우선, 파일을 read할 임시 버퍼를 만든다.
char buf[BUFFER_SIZE];
- read한 버퍼를 저장해 둘 static 버퍼를 만든다.
static char *backup
- read(fd, buf, BUFFER_SIZE); 를 해서 버퍼만큼 라인을 읽는다. 그리고 buf를 정적 변수 backup에 백업한다.
- backup 안에 개행문자가 있는지 없는지 검사한다.
- 개행문자가 있으면 다음 단계로 넘어가고, 없으면 개행문자가 있을 때가지 3번으로 돌아가 파일을 계속 읽는다.
- 이와 동시에 기존에 백업한 내용에 계속 합친다.
- 개행문자가 있는 backup을 개행문자 전과 후로 잘라서, 개행문자 전까지는 line에 주고, 개행문자 후는 다시 static 변수 backup에 넣는다.