[42 Seoul] Get Next Line 과제를 수행하기 전 알아야 할 내용
업데이트:
42의 Get Next Line 과제를 수행하며 정리하는 내용이다. 코로나로 인해 장기간 닫혀있던 42 클러스터의 문이 열려서 모처럼 공부를 하게 되었는데, 코드 자체를 너무 오랜만에 보니 적응이 하나도 안 되어 하나하나 정리하며 공부하기로 했다.
과제를 수행하기 전 알아야 할 내용
파일 디스크립터(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 변수 (정적 변수)
-
변수를 선언할 때 static 키워드를 붙여 선언한다.
static int num
-
메모리의 데이터 영역에 저장되어 프로그램이 종료될 때까지 남아있는 변수다.
-
함수를 벗어나도 해당 변수는 사라지지 않고 계속 유지된다. 하지만 함수 내부에서 선언되었다면, 다른 함수에서는 이 값을 참조할 수 없다. 또한 함수의 시작이 아닌 프로그램의 시작 시 할당이 되며, 프로그램이 종료될 때 해제된다.
-
함수 내에서
static int num = 0
식으로 초기화하면 프로그램이 시작될 때 변수를 초기화하며, 함수가 호출될 때는 변수를 초기화하지 않는다. (여러 번 함수를 실행하더라도 그 변수가 또 초기화되지 않는다) -
정적 변수는 초깃값을 지정하지 않으면 0으로 알아서 초기화된다.
-
이번 과제에서는, 다음 line을 읽을 시작 주소를 계속 저장할 수 있도록 백업 버퍼를 만들어 static 변수로 선언해야 한다.
-
정적 변수를 전역 변수로 사용한다면 이미지 출처 : https://dojang.io/mod/page/view.php?id=690
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
에 넣는다.
참고자료
- 이 글의 내용은 상당 부분 Daehyun Lee님의 블로그 를 참고하여 작성하였습니다. 많은 도움이 되는 포스트였습니다. 감사합니다.
- 정적 변수에 대한 일부 설명은 https://dojang.io/mod/page/view.php?id=690 에서 인용하였습니다.
댓글을 남겨주세요