FT_PRINTF - Bonus
FT_PRINTF - Bonus
개요
mandatory에서는 가변 인자만 출력할 수 있었습니다. 보너스 파트에서는 서식지정자에 해당하는 가변 인자 말고도 여러 플래그들을 사용해 출력을 해내야 합니다.
7가지의 플래그를 구현하는 것도 처음에는 어려울 수 있습니다. 하지만 가장 어려운 것은 플래그들의 조합, 서식지정자와 플래그의 조합 등을 전부 고려해야 하기 때문입니다. 생각해야 할 경우의 수가 너무 많아서 대부분 보너스 파트는 시도하지 않습니다.
소스 코드 제한이 없기 때문에 어떻게든 구현할 수는 있지만, 굉장히 복잡해지므로 수정하기도 어렵고 하나를 고치면 다른 부분에서 문제가 생기는 순회를 하게 될 겁니다.
목표
Manage any combination of the following flags: '-0.' and minimum field width with all conversions
다음 플래그들의 조합 (any combination) 을 구현하세요 : '-0.', 그리고 각 서식 지정자별 최소 폭
Manage all the following flags: '# +' (yes, one of them is a space)
다음 플래그를 모두 구현하세요 : '# +' (맞아요, 한 개는 공백이에요)
구현 전 사전 지식
1. 플래그
2. 플래그의 조합
3. 서식지정자와의 조합
1. 플래그
- '*' : 서식지정자별 최소 폭을 결정합니다. 가변 인자로 폭을 결정합니다.
- '0123456789' : 가변 인자로 최소 폭을 결정할 필요 없이 플래그 자리에서 숫자로 사용할 수 있습니다.
- '-' : 출력문을 왼쪽정렬합니다. 기본적으로 출력문은 오른쪽 정렬입니다.
- '0' : 최소 폭은 기본적으로 공백 문자로 표현되는데 '0' 플래그는 공백을 '0' 숫자로 표시합니다.
- '.' : 출력할 값의 정밀도를 위한 자릿수를 설정합니다. 설정한 정밀도 만큼 자릿수를 '0'으로 채웁니다. 출력 값의 길이가 더 길다면 정밀도 플래그는 동작하지 않습니다. 음수는 올 수 없습니다(컴파일 에러).
- '#' : x, X 서식지정자에 한해서 '0x' 접두사를 붙입니다.
- ' ' : 출력문을 나타내기 전에 공백을 표시합니다.
- '+' : d, i 서식지정자에 한해서 양수일 경우 '+'를 접두사로 붙입니다.
2. 플래그의 조합
- '0' : '.'와 '-'에게는 무시된다.
- ' ' : '+'에게 무시된다.
3. 서식지정자와의 조합
c | s | p | d | i | u | x | X | % | |
- | O | O | O | O | O | O | O | O | O |
0 | UB | UB | UB | O | O | O | O | O | O |
. | X | 문자열 제한 | UB | O | O | O | O | O | 무시됨 |
# | UB | UB | UB | O | O | UB | O | O | 무시됨 |
공백 | UB | UB | UB | O | O | UB | UB | UB | 무시됨 |
+ | UB | UB | UB | O | O | UB | UB | UB | 무시됨 |
확인해야 할 것은 서식지정자 s의 '.' flag입니다. 보통 다른 서식지정자에서 부족한 출력 길이를 '0' 숫자로 채워주는 역할을 했습니다만, s에서는 문자열의 최대 길이를 제한하는 것으로 작동합니다.
또 '%'는 무시되는 플래그에 대해서 cc 명령어로 컴파일할 시, 에러 경고를 해주지 않았습니다. 단지 플래그가 어떠한 역할도 하지 않는 것만 확인할 수 있었습니다.
그리고 c와 p서식 지정자의 한해서 '.' flag를 사용할 때, '.'뒤에 정밀도 값을 입력했을 때만 오류가 발생하지, 값을 입력하지 않고 '.'만 찍으면 경고조차 하지 않습니다.
구현
pesudo code
typedef struct s_print
{
va_list vlist;
int plen;
int space;
int hash;
int minus;
int plus;
int zero;
int dot;
int precision;
int width;
} t_print;
const char *set_flags(t_print *ps, const char *f)
{
구조체의 플래그 변수들을 0으로 초기화 한다.
while 문자열의 플래그를 하나씩 확인한다.
{
if (*f == '#')
ps->hash = 1;
else if (*f == '.')
ps->dot = 1;
else if (*f == '-')
ps->minus = 1;
else if (*f == '0')
ps->zero = 1;
else if (*f == '+')
ps->plus = 1;
else if (*f == ' ')
ps->space = 1;
else if (ft_isdigit(*f))
최소폭을 처리하는 함수를 호출한다.
f++;
}
서식지정자를 확인한다.
문자열을 반환한다. (문자열의 위치)
}
printf의 첫번째 인자로 전달받은 문자열을 확인하면서, 플래그와 서식지정자를 체크하는 flag 역할을 하는 구조체를 만들고 이를 함수에서 확인했습니다.
이후의 다른 함수에서 플래그의 조합이 무시되는 것은 함수에서 따로 확인해 주어야 합니다!
마치며
저는 소스 코드 파일을 20개 정도로 사용하여 bonus를 구현했습니다. mandatory는 5개로 할 수 있었는데, 보너스는 워낙 경우의 수가 많다보니 예외 사항이 하나 생기면 파일이 하나 늘어나는 듯한 느낌으로 풀어낸 것 같습니다.
그럼에도 불구하고 8점이 깎여버렸는데, 어디에서 찾아야 할지도 감이 안와서 만점을 받는 것은 미뤄두고 있습니다. 이렇게 파일이 많다보니 자세히 설명을 남기고 싶은 블로그에도 올릴 염두가 나지않아서 가장 중요하다고 생각되는 풀이 방법으로 구조체를 소개했습니다.
플래그를 어떻게 처리하는지 정말 감이 안잡혔는데 구조체를 하나 쓰기 시작하면 아마 생각에서 막히는 부분은 없을 것입니다. 보너스를 구현하는 것은 정말 쉽지 않은 선택입니다. 하지만 정말 실력이 느는 것을 체감할 수 있을 겁니다.