[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 변수로 선언해야 한다.

  • 정적 변수를 전역 변수로 사용한다면 img 이미지 출처 : 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일 때도 함수가 제대로 작동해야 한다.

작동 구조 고민

  1. 우선, 파일을 read할 임시 버퍼를 만든다.
    char buf[BUFFER_SIZE];
    
  2. read한 버퍼를 저장해 둘(백업할) static 버퍼를 만든다.
    static char *backup
    
  3. read(fd, buf, BUFFER_SIZE); 를 해서 버퍼만큼 라인을 읽는다. 그리고 buf를 정적 변수 backup에 백업한다.
  4. backup 안에 개행문자가 있는지 없는지 검사한다.
  5. 개행문자가 있으면 다음 단계로 넘어가고, 없으면 개행문자가 있을 때가지 3번으로 돌아가 파일을 계속 읽는다.
    • 이와 동시에 기존에 백업한 내용에 계속 합친다. (이 기능을 구현하는 함수 추가)
  6. 개행문자가 있는 backup을 개행문자 전과 후로 잘라서, 개행문자 전까지는 line에 주고, 개행문자 후는 다시 static 변수 backup에 넣는다.

참고자료

  • 이 글의 내용은 상당 부분 Daehyun Lee님의 블로그 를 참고하여 작성하였습니다. 많은 도움이 되는 포스트였습니다. 감사합니다.
  • 정적 변수에 대한 일부 설명은 https://dojang.io/mod/page/view.php?id=690 에서 인용하였습니다.

댓글을 남겨주세요