get next line

hhkim·2021년 5월 24일
0

42cursus

목록 보기
2/20
post-thumbnail

테스터

https://github.com/C4r4c0l3/gnl-war-machine-v2019.git
https://github.com/mrjvs/42cursus_gnl_tests.git
https://github.com/DontBreakAlex/gnlkiller.git
https://github.com/Mazoise/42TESTERS-GNL.git
https://github.com/Tripouille/gnlTester.git
https://github.com/charMstr/GNL_lover.git


함수 원형

int get_next_line(int fd, char **line);
  • fd: 파일 디스크립터(참고1, 참고2)
  • line: 읽어들인 문자열
    • 여기에 새로운 메모리를 할당해서 읽어들인 문자열을 저장하며, 그 주소를 따로 리턴하지 않기 때문에 이중 포인터가 필요하다.
  • 리턴값
    • 1: 개행문자까지 한 줄을 읽어들였을 때
    • 0: 파일 끝(EOF)까지 한 줄을 읽어들였을 때
      • 파일의 끝에 다다랐다고 해도 static 변수에 개행 문자가 남아 있다면 1을 반환해야 한다.
    • -1: 오류 발생

컴파일

gcc -Wall -Wextra -Werror -D BUFFER_SIZE=32
get_next_line.c get_next_line_utils.c
  • -D BUFFER_SIZE=xx 플래그
    • -D는 define 옵션으로, 소스 코드 내에서 쓰일 매크로를 컴파일 시에 정의할 수 있다. (#define과 동일)
    • 평가 시에 버퍼 사이즈를 임의로 조정

구현

  • 반복문을 실행하여 EOF까지 한 줄씩 읽어들이면 파일 전체를 읽어들일 수 있다.
    • 한 줄은 개행문자(\n) 기준
    • 가장 작은 데이터 단위로 읽어들이다가 새로운 줄을 만나면 그 전까지 읽은 줄을 리턴한다. (line에 복사)
    • 개행문자는 제외 (문자열에 \n만 있는 경우 처음에는 빈 문자열, 두 번째에도 빈 문자열을 할당한다.)
    • 파일이 비어 있는 경우에는 빈 문자열을 할당한다.
  • 한 번 BUFFER_SIZE만큼 파일을 읽어들였을 때 여러 개의 개행 문자가 포함되어 있을 수 있으므로, 이때 읽어들인 데이터는 함수의 실행이 종료된 후에도 남아있어야 한다. (static 변수를 사용해야 하는 이유)
  • static 포인터를 만들고 문자열을 계속 이어 붙인다.

static 변수

  • 프로그램 실행과 생명 주기가 같다.
  • 함수의 실행이 끝나도 값이 유지된다.
  • 0으로 자동 초기화된다.
  • 정적 전역 변수의 사용 범위는 해당 소스 코드로 제한된다.

static 포인터

  • 포인터가 가리키는 주소의 값을 변경할 때, 이전에 할당된 메모리를 해제하지 않으면 누수가 발생한다.

fd 값 유효성 체크

  • 0 ~ OPEN_MAX
    • OPEN_MAX 값은 플랫폼에 따라 다른데, 현재 리눅스 시스템에서는 deprecated된 상태
    • OPEN_MAX 값이 너무 큰 경우, fd가 그 범위 내에 있어도 오류가 발생한다.
  • ulimit -n, getconf OPEN_MAX: 한번에 열 수 있는 파일 최대 크기 확인 (참고)
    • 클러스터 맥은 256

BUFFER_SIZE

  • read 함수는 반드시 컴파일 시에 정의된 BUFFER_SIZE를 사용해야 한다.
    • read 1회 실행 시 BUFFER_SIZE만큼 읽어들인다.
    • read를 한 번 실행했을 때 읽어들인 버퍼에 개행 문자가 여러 개라면 다음 실행 때 read를 또 실행하는 것은 비효율적이므로, static에 저장된 문자열을 먼저 검사하여 실행 여부를 결정한다.
  • 버퍼를 단순 캐릭터 배열로 선언하는 경우, BUFFER_SIZE가 스택 메모리 영역을 넘어서면 segfault가 발생한다.
    • 이 경우를 대비해서 힙 메모리 영역에 버퍼 사이즈가 할당될 수 있도록 동적 할당을 한다.
    • 스택 최대 사이즈는 ulimit -s로 확인
      • 8192 kb == 8388608 b
      • 최대 약 800만 바이트로 스택 크기가 1000만 정도로 크게 주어지는 경우 segfault가 발생한다.

read()

ssize_t read(int fd, void *buf, size_t count);
  • fd: 파일 디스크립터
  • buf: 읽어들인 데이터를 저장할 메모리 영역
  • count: 읽어들일 바이트 수
  • 성공 시 읽어들인 바이트 수, eof에 도달하여 더이상 읽을 바이트가 없으면 0, 실패 시 -1을 반환한다.

ssize_t: signed size_t


보너스

  • static 변수를 하나만 사용
  • 여러 개의 fd를 동시에 작업할 수 있어야 함

구현

  • OPEN_MAX 크기의 static 포인터 배열 생성
  • fd와 동일한 인덱스의 배열 요소에 문자열을 저장한다.

참고

https://velog.io/@two_jay/getnextline-tcrgemrf
https://www.notion.so/975319c9434342409073c3d41f8729ab
https://www.notion.so/get_next_line-4d3eba5f5d2d4becb0a2fa058d67c643#56d19da82b7847a89d0eca867a9a2484
https://epicarts.tistory.com/154
https://www.notion.so/42SEOUL-Get_Next_Line-by-junghan-e1f2d44d61974d5bbeaba9ae6f9fa4b1

0개의 댓글