과제를 시작하기 전 ..
-
파일 디스크립터 (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 변수로 선언해야 한다.
- 위키디피아의 정적변수 설명
- 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일 때도 함수가 제대로 작동해야한다
- GNL 프로젝트는 open함수로 파일을 열었을 때 받는 파일 디스크럽터(fd)를 사용하여 한 줄씩 line에 저장하는 함수를 구현하면 된다고 할 수 있다. (정확한 의미로는 line의 포인터가 한 줄을 가리키게 만들어야 한다는 뜻)
static 변수
- static 변수를 한 줄로 요약하자면, 지역변수와 전역변수 둘의 성질을 같이 가지고 있다고 생각하면 된다.
- static 변수는 지역변수와 같이 선언된 함수 내에서만 사용이 가능하다.
- 그러나 한 번만 초기화하며, 전역 변수처럼 프로그램이 종료될 때까지 메모리 공간에 존재한다.
- 지역 변수와는 달리, 해당 함수가 종료되거나 반환을 하더라도 소멸되지 않는다.
- 변수를 선언할 때 static 키워드를 붙여 선언한다.
static int num
- 메모리의 데이터 영역에 저장되어 프로그램이 종료될 때까지 남아있는 변수다.
- 함수를 벗어나도 해당 변수는 사라지지 않고 계속 유지된다. 하지만 함수 내부에서 선언되었다면, 다른 함수에서는 이 값을 참조할 수 없다. 또한 함수의 시작이 아닌 프로그램의 시작 시 할당이 되며, 프로그램이 종료될 때 해제된다.
- 일반 지역 변수가 할당되는 stack 부분이 아니라 data 부분에 할당된다.
- 함수 내에서
static int num = 0
식으로 초기화하면 프로그램이 시작될 때 변수를 초기화하며, 함수가 호출될 때는 변수를 초기화하지 않는다. (여러 번 함수를 실행하더라도 그 변수가 또 초기화되지 않는다)
- 정적 변수는 초깃값을 지정하지 않으면 0으로 알아서 초기화된다. 구조체를 static으로 선언한 경우 그 안의 멤버변수들이 0으로 초기화된다. (지역 변수는 초기화하지 않으면 쓰레기값으로 초기화된다.)
Logic
- 우선 파일을 read 및 저장, 반환값을 저장할 수 있도록 구조체를 만든다.
typedef struct s_buffer
{
char *buf;
size_t pos;
size_t size;
} t_buffer;
typedef t_buffer t_line_buffer;
typedef t_buffer t_read_buffer;
- 파일을 읽는 read하고 저장할 static 구조체를 선언한다.
static t_read_buffer rb[OPEN_MAX];
- read한 char를 ‘\n’ 문자가 나올 때까지 저장 후 리턴할 구조체를 만든다.
t_line_buffer lb;
- read(fd, buf, BUFFER_SIZE); 를 해서 버퍼만큼 라인을 읽는다. 그리고 read buffer의 buf에 저장한다.
read(fd, buf, BUFFER_SIZE);
- read buffer의 buf에서 한 글자씩 개행문자가 있는지 확인한다.
- 개행문자가 없다면 읽은 한 문자를 line buffer에 넣어준다. 개행문자가 있거나 파일의 끝인 경우애는 line 버퍼에 넣어주는 것을 멈추고 이 과정을 멈춘다.
- BUFFER_SIZE보다 큰 길이의 파일이 들어온 경우에는 다시 read를 하여 read buffer를 덮어씌우고 위의 과정을 이어간다.
- 함수를 다시 호출한 경우 static 변수인 rb에 의해 저장되어있던 곳부터 다시 시작한다.