Search
Duplicate

ft_printf 탐구하기

간단소개
팔만코딩경 컨트리뷰터
ContributorNotionAccount
주제 / 분류
C
태그
ft_printf
Scrap
8 more properties
c의 간단하면서도 가장 보편적으로 사용되는 국밥 같은 존재 'printf'를 구현하는 과제를 했습니다
단순 구현은 금방 끝났지만 보너스 노려보겠다고 무려 3주나 뇌절했습니다...
파싱이라는 경험이 처음이라 재미있었습니다
단순 구현 부분은 간단합니다
주어진 문자열을 차례대로 읽어나가며 하나씩 출력하다가 format string에 따라서 가변 인자를 읽어오고 출력하는 것입니다
format string이란 이 다음에 출력되어야 하는게 어떤 데이터타입인지 표시하는것과같은데요
이곳에 표로 잘 정리되어있어서 참고했습니다
이 과제에서는 가변 인자에 대한 개념이 필요합니다
가변 인자라 함은 함수에 주어지는 인자에서 고정되는 부분이 아니라 얼마든지 개수가 변할 수 있는 부분을 말합니다
그리고 이를 다룰 수 있는 매크로들이 들어있는 헤더 <strdarg.h>가 있습니다
va_list
가변 인자를 담고 있을 수 있는 구조체입니다, 이 구조체에 매크로를 사용함으로써 포인터 연산을 하고 그 연산을 토대로 가변 인자를 사용합니다
va_start(va_list ap, last)
va_list를 초기화합니다, 인자로는 va_list 변수와 함수에 주어지는 고정 인자 중 마지막 고정 인자입니다
아마 마지막 고정 인자를 기준으로 다음부터 순서대로 stack에 쌓으면서 초기화를 하는 것 같아서
마지막 고정 인자 대신 이전 고정 인자를 넣어주면 어떻게 되나 궁금했는데 컴파일 에러가 발생합니다
va_arg(va_list ap, type)
가변 인자 목록에서 type의 크기만큼 값을 읽어옵니다, 가변 인자로 적어준 type과 다른 type을 적어주면 엉뚱한 값이 출력되어 나옵니다
va_end(va_list ap)
사용한 va_list를 null로 만듭니다, windows에서는 별 상관없는 함수지만 운영체제에 따라서 이 함수를 호출해야 하는 경우도 있다고 합니다
va_copy(va_list dest, va_list src)
dest에 src를 복사합니다, 단순히 가변 인자 목록을 복사해서 넘길 뿐만 아니라 src가 현재 가리키고 있는 위치까지도 복사해서 넘겨줍니다
char형 가변 인자는 va_arg에서 int type으로 읽어와야 한다는 것만 주의하면 어려운 부분은 없습니다
왜 int로 읽어와야 하는지 이유는 못 찾았지만 개인적으로 추측건대 type의 크기가 4, 8과 같이 배수로 되어있다면 문제없지만 char처럼 1로 되어있다면 인자를 읽고 나서 짝수로 맞아떨어지지 않으니 불안정해서 int를 가장 최소단위로 맞춘 게 아닐까 싶습니다 어차피 char를 4byte에 저장해도 커버하고 남으면 남지 문제 될 건 없으니까요
보너스 부분에서는 입력이 단순 format string뿐만 아니라 여러 flag들도 추가되어서 들어옵니다
% flags widht precision specifier
위와 같은 순서로 입력이 들어오므로 입력요소들 별로 처리하는 함수를 따로따로 만들어주는 계획을 세웠습니다
처음음에 flag 부터 precision까지 순서대로 읽어오고 이를 기반으로 수정할것은 수정하고 우선순위로 무시될것은 무시되도록 처리하면서 마지막 specifier에 따라 출력하는 함수를 따로 호출하는식으로 작성했습니다
윈도우에서 테스트할때 주의점이라면 unix와는 달리 %p로 출력을 했을때 자릿수가 적게나옵니다 unsigned int 범위까지만 나오는데, 이 부분만 주의하면 크게 어려운점은 없었습니다
처음에는 유효하지 않은 flag가 입력되었을때 컴파일이 되지 않는것도 오류값을 반환하도록 구현을 해야하나 싶었지만 slack에서 다른분들께 질문드리면서 대화해보면서 '컴파일러가 표시하는 오류' 와 '함수가 표시하는 오류' 를 따로 생각해야한다는것을 알게되었습니다
그래서 우선 컴파일 옵션을 넣지 않은 상태에서 결과값을 중심으로 구현하였고 unix같은 경우에는 precision이 여러번 들어오거나 flag가 나중에 입력이 들어와도 출력이 되었는데 윈도우에서는 flag 입력이 유효하지 않으면 가변인자 처리를 중단하고 specifier이후부터 그냥 일반적인 문자열처럼 출력한다는것도 알게되었습니다
변수 이름도 줄일 수 있는 건 최대한 줄이고 읽어나갈 때도 여러곳을 동시에 봐야하지 않도록 직관적이게 구현하려 노력하긴했는데 읽기 편한것이라는게 사람마다 다르다보니 오히려 혼란만 키운것같긴하네요