열렬히.뛰기

get_next_line

개요 & 필요개념

버퍼를 통해 텍스트 파일의 줄들을 한 줄씩 출력하는 프로그램 만들기.

파일 디스크립터

컴퓨터 운영 체제에서 파일을 식별하고 관리하기 위해 사용하는 정수 값.

일반적으로 파일이나 소켓과 같은 입출력 장치에 대한 참조를 나타냄. 프로세스가 실행 중에 파일을 Open하면 커널은 해당 프로세스의 파일 디스크립터 숫자 중 사용하지 않는 가장 작은 값을 할당해준다. 그 다음 프로세스가 열려있는 파일에 시스템 콜을 이용해서 접근할 때, 파일 디스크립터(FD)값을 이용해서 파일을 지칭할 수 있다.

  • 0번 파일 디스크립터는 표준 입력(STDIN)을 나타냄.
  • 1번 파일 디스크립터는 표준 출력(STDOUT)을 나타냄.
  • 2번 파일 디스크립터는 표준 오류(STDERR)를 나타냅니다.
  • 그 다음부터는 open()으로 열은 파일 순서대로.

read() 함수

read(fd, buff, BUFF_SIZE);

fd : 파일 디스크립터, open하고 얻은 값.

buff : 읽어드릴 데이터를 저장할 버퍼. 배열이라고 생각하면 된다.

BUFF_SIZE : 데이터의 최대길이. 매크로를 이용해 미리 설정해준다.

gcc -d 플래그

  • 프로그램 외부에서 #define을 정의하여 컴파일 시 반영할 수 있다.

static 변수

  • 프로그램 시작 시 할당, 끝날 때 파괴되는 변수.
  • 초기화가 1번만 이뤄진다.
  • 함수 밖에서 선언시, 소스파일 내부 어디서든 사용 가능.
  • 함수 안에서 선언 시, 해당 함수 안에서만 사용 가능

필수파트

구현

Yujin
IVe is coming back
20230410

다음과 같은 문장이 있고, 버퍼 사이즈가 10이라고 해보자.

  1. 처음으로 읽을 문장은 다음과 같다 : Yujin\nIVE
  2. 여기에 backup을 붙인다.
  3. 처음부터 \n까지의 파트를 출력한다.
  4. 남은 backup은 다음 get_next_line을 위해 보관한다.

이 과정을 다시 반복한다.

mermaid
flowchart TB
	backup & text --> total --> return & backup2
	backup2 & text2 --> total2 --> return2 & backup3
	backup3 & text3 --> total3 --> return3 & backup4

주의사항

  1. .c 파일이 2개 밖에 주어지지 않는다.

  2. gnl을 위해 부가적으로 쓸 함수는 get_next_line_utils 파일만 저장할 수 있다.

  3. leaks() 를 조심할 것. 굉장히 꼼꼼히 잡는다.

  4. 처음 backup의 크기를 선언할 때, 정적 배열로 선언하면 최댓값이 정해져 있음.

    그러나 중요한 것은 해당 부분 역시 os마다 다르기 때문에, 해당 부분을 따로 설정할 필요가 있음.

    (매크로를 이용해 설정)

전체 코드

get_next_line.c

get_next_line.h

get_next_line_utils.c

보너스파트 - 1번째 풀이

구현

여러 파일 디스크립터(fd)가 나올 때 간단하게 짜는 방법.

이차원 배열을 활용해 파일 디스크립터가 들어갈 2차원 배열 backup을 만들어준다.

이때의 배열의 크기는 OPEN_MAX로 지정한다.

나머지는 기본 파트와 전부 동일.

주의사항

파일 디스크립터를 과연 몇 개까지 열 수 있는가, 즉 OPEN_MAX 값에 대한 논쟁이 있다.

OPEN_MAX 값을 활용하게 될 경우, “limits.h” 에 정의되어있는 OPEN_MAX 값을 활용하게 된다.

그러나 limits.h 에서 OPEN_MAX가 정의되지 않은 운영체제가 존재한다.

  • 이 경우에는 헤더에 임의로 정의해둔 OPEN_MAX 값을 활용하게 된다.
  • 각자의 컴퓨터에서 제한되어 있는 OPEN_MAX 값이 있다.
  • 이를 설정하는 방법은 다음과 같다.
bash
ulimit -a       # 프로세스의 자원 한도(soft 설정)을 모두 보여줌
ulimit -n 49152 # open_max 값을 정하는 방법

Mac 기준으로 49152개가 한계인 것으로 추측된다. (dup2() 함수를 써도 마찬가지)

반론

  1. 연결리스트의 단점인 시간복잡도의 한계를 뛰어넘을 수 없다.

  2. norm에 걸리게 된다.

  3. 이 함수를 만드는 목적은 libft에 삽입하기 위함이다. (문제에 나와있음)

    과연 그 정도로 많은 파일을 열 일이 있을..까?

전체 코드

get_next_line_bonus.c (1)

get_next_line_bonus.h (1)

get_next_line_utils_bonus.c (1)

보너스파트 - 2번째 풀이

구현

여러 파일 디스크립터(fd)가 나올 때 안전하게 짤 수 있는 방법.

연결리스트를 활용해 파일 디스크립터가 들어갈 backup을 만들어준다.

leaks가 나는 것을 최대한 막아야 하는 것이 최대 과제라고 할 수 있다.

앞의 풀이와는 달리 가변적인 자료구조라고 할 수 있다.

주의사항

  1. 한 함수 안에 너무 많은 것을 쑤셔넣어야 한다.
    • 함수 하나 당 25줄의 제한, 변수 5개 이상은 사용 불가.
    • 한 소스 당 함수는 최대 5개까지 이용 가능
    • 이용가능한 .c 소스 파일은 딱 2개. 즉 함수 10개가 최대.
    • 이 상황에서 과연 좋은 설계가 가능할까?
  2. 효율성의 문제
    • limits.h 에 정의된 10240개 이상의 파일을 동시에 열어야 한다.
    • 이때 O(N)의 시간복잡도가 발생한다.
    • 자료구조를 유지하기 위한 시간도 별도로 고려해야 한다.
    • 즉, 시간이 너무 오래 걸린다.

전체 코드

get_next_line_bonus.c (2)

get_next_line_bonus.h (2)

get_next_line_utils_bonus.c (2)

github.com/InryeolChoi/42_getnextline