Getnextline 만들기
42 Seoul Getnextline
42서울 두번째 과제로 진행했던 getnextline은 '\n'까지의 한 줄을 읽고 이를 출력하는 함수를 만드는 것이다. gets, fgets와 유사하지만 이를 사용하지 못 하고 systemcall인 read함수를 사용해야 하기에 read 함수의 결과값이 어떻게 나오는지를 먼저 확인하고 각각의 경우에 과제에서 요구하는 한 줄 str으로 만들 것인가를 생각하는 순서로 진행했다.
1.Read() function
https://man7.org/linux/man-pages/man2/read.2.html
위의 man 페이지에 나와있는 read function 설명도 이제보면 명료하지만 read함수가 낯설었던 과제 당시에는 충분히 이해되지 않아 read의 입출력을 아래와 같이 조사했다.
#include <unistd.h>
char *buffer[BUFFER_SIZE];
check = read(fd, buffer, size);
파일 또는 stdin인 fd, 모두 '\0'으로 초기화된 buffer[]에 위와 같이 read 함수를 적용했을 때 check(반환값)과 buffer의 변화를 생각할 수 있는 경우의 수로 나누어
check = -1 일때, check = 0일 때, 0 < check < size 일 때, check = size일 때 buffer의 값이 어떻게 변화했는지를 직접 확인한 후 각각의 경우의 의미와 그때 getnextline 이 반환해야하는 이번 줄 문자열 (char *line)은 어떻게 처리해야하는지를 적었다. 그리고 다시 정리한 페이지를 pseudo code로 보고 과제를 수월하게 시작할 수 있었다.
2.Static variable
getnextline에서 read를 호출할 때는 지금 읽는 size 바이트내에 newline이 있을지 없을지 모르는 상황이다. 호출한 후에는 file descriptor의 offset이 증가하여 만약 size 바이트의 중간에 newline이 있었다면 newline 이후의 문자들을 저장해야 다음 getnextline때 정확한 한 줄을 출력해줄 수 있다. 이를 해결하기 위해 subject에서 언급된 static varaible을 사용하였다.
int func1(void)
{
static int var;
var++;
return (var);
}
위와 같이 static 타입으로 선언된 var은 언제나 초기화가 된다. 위의 int형의 경우 0 값을 가지게 된다. runtime에서 최초로 func1이 호출될 때, func1은 var이 0으로 초기화, 1로 증가, 1반환을 하게 된다.
일반적인 (auto) 변수들과 다르게 static 변수는 이후 다시 func1이 호출되었을 때 0으로 초기화되지 않고 이전 func1이 호출되어 반환했을 때의 값을 유지한다. 위의 예시에서 func1 첫 호출에서 var 값이 1인 상태로 종료되었기에 func1이 다시 호출된다면 var이 2로 증가, 2반환되는 결과를 얻게 된다.
3. Bonus problem & solution
위의 방법으로 여러 fd를 처리하는 bonus까지 작성했으나 기계채점에서 bonus part KO가 나왔다.
첫번째 생각은 mandatory에서 사용한 static variable과 bonus에서 사용한 static variable의 이름이 달라 이를 static variable 2개로 기계가 인식했는가? 하는 의심이었다. 바로 bonus part 코드를 복붙하여 (이전에는 평가시 수월한 설명을 위해 간단한 버전인 mandatory를 남겼었다) 다시 제출했지만 바로 다시 KO를 받았다.
이후 여러 카뎃들과 같이 이야기하면서 추측한 문제점들은
잘못된 fd를 바로 종료하지 않는다 - 내가 작성한 함수는 음수의 fd값이 들어와도 read에 집어넣고 read 결과에 따라 유효하지 않은 fd임을 확인하고 종료되는 형태였는데, 이 과정에서 메모리할당등의 작업이 발생하는 것이 문제일 수 있어 조건문으로 바로 반환되도록 수정했다.
null-termination - read 결과인 buffer는 언제나 null로 종료되지 않는데, 굳이 한칸을 더 써서 '\0' 문자를 입력하지 않고 검사하여 처리하는 방법을 사용했었다. 기계채점에서 사용한 메모리를 검사하는 과정에서 null-terminated 형태가 아니어서 문제가 되었나라고 생각하여 사이즈를 1 증가하여 '\0'으로 감싸주었다.
EOF 판단 - 이전에는 작성한 testfile이나 stdin으로 read 결과값을 조사하고 EOF을 판단했었는데, 뒤의 과제인 push swap bonus를 하는 과정에서 pipe로 fd를 넘겨주는 경우 EOF를 판단하는 조건을 다르게 해야함을 발견했다.
위의 문제점들을 모두 수정한 결과 bonus part도 기계에서 통과할 수 있었다. 평가 시간의 소모를 줄이기 위해 위의 3가지를 모두 수정해서 정확히 셋 중 어느 것이 문제인지를 알 수 없다. 아마 1 또는 3번이 문제라 생각하고 fd를 추가하는 파트이기에 1번일 수도 함수의 중간과정을 생략한 입력, 출력만 보면 세번째 수정사항만이 변경되기에 3번이 기계에서 걸린 문제점일 수 있다. paco tester는 모두 통과했는데 bonus 기계채점에서 문제가 발생한다면 위의 세가지를 점검하는 것을 추천한다.
Comments
Join the discussionNo comments yet. Be the first to comment.