방금 ft_printf 평가를 받다가, 코드에 대한 중요한 comment를 받게 되어서 쓰는 글
대략적인 코드의 흐름은 이렇다.
<ft_printf.c>
- ft_printf 함수에서 하나의 고정인자와 가변인자를 매개변수로 받는다.
- va_list 가변 인자 포인터 변수 ap와, 각 가변인자에 대한 출력 길이를 임시 저장할 변수를 선언한다.
- va_start로 가변인자를 가리키게 한다.
- 가변인자에 대한 출력 길이 임시 저장할 변수 += ft_parse_format
- va_end로 가변인자의 파싱이 끝났음을 알려준다.
<ft_parse_format.c>
- 고정 인자의 문자열의 문자들이 널 종료 문자를 만날 때 까지 순차적으로 탐색한다.
- '%' 문자를 만났을 경우, 서식 지정자에 대한 처리를 수행한다
-ft_parse_format 함수 호출, '%' 다음 인덱스 문자의 가변 인자 목록 포인터를 매개변수로 넘겨준다
-맨 끝에 '%'만 있을 경우 다음 문자는 NULL이므로, break- '%'문자를 발견하지 못할 경우, 문자를 순수 출력한다.
<ft_parse_type> 함수는 다음과 같은데 어떤 점이 문제가 될 수 있을까?
int ft_parse_type(const char c, va_list ap)
{
int cnt;
cnt = 0;
if (c == 'c') //문자
cnt += ft_print_ch(ap);
else if (c == 's') //문자열
cnt += ft_print_str(ap);
else if (c == 'p') //포인터의 메모리 주소
cnt += ft_print_mem(ap, c);
else if (c == 'd' || c == 'i') //부호가 있는 10진 정수, scanf에서 역할이 다름
cnt += ft_print_int(ap, c); //d : 10진수 입력받음, i : 10/8/16진수 입력 받음
else if (c == 'u') //부호가 없는 10진 정수
cnt += ft_print_unsigned_int(ap, c);
else if (c == 'x' || c == 'X') //부호가 없는 16진 정수 (소문자 / 대문자)
cnt += ft_print_hexadecimal(ap, c);
else if (c == '%') //형식 지정에 필요한 문자, %기호 출력
cnt += write(1, "%", 1);
return (cnt);
}
이러한 조건문을 쓸 때는 주의할 점이 있다.
바로, "모든 조건에 해당하지 않을 경우에 대한 처리."
예를들어, "%m"과 같은 가변인자 목록 포인터를 매개변수로 넘겨 받았다면 어떻게 처리가 될까?
위 로직만으로만 봤을 때는, 모든 조건문에 해당하지 않기 때문에 아무 것도 출력 되지 않는다. 즉, 무시되는 것이다. 그러므로 else문을 마지막에 추가해서, 문자 그대로 write 해주는 부분이 필요하다.
그리고 매개변수를 ap로 넘겨주는 것 보다는, va_arg로 바로 넘겨주는 것이 더 깔끔하고 간단한 코드가 될 수 있었다!
write는 오류 시 -1을 반환하기 때문에 % 기호 출력 시 사용 된 write 함수에 대한 예외처리도 필요하다.
다행히 3개의 test기를 돌려 봤을 때 모두 통과가 되었기 때문에 fail을 받지는 않았다. 그런데 아주 중요한 부분을 놓친 것 같다!!
(jonghpar님 감사합니당 😆)