# 구현을 함에 있어서 기본적인 서식지정자만 구현을 해 주었다.
printf(”%d %d %d”,1,2,3) 에서 인자를 몇개를 넣어도 잘 돌아간다.
printf의 프로토타입을 확인해보면 다음과 같다.
int printf(const char* format, ...)
이때 두번째 인자로 사용되는 … 이 가변인자, 혹은 가변 파라미터라고 불리는 것이다.
먼저 가변 인자 함수를 만들기 위해서는 stdarg.h 헤더파일을 포함해야한다. 이 헤더 파일에 가변인자 함수를 만들 때 필요한 각종 매크로 들이 정의되어 있다. 또한 최소 1개 이상의 고정인수 가 있어야 한다.
va_list : 각 가변 인자의 시작 주소를 가리킬 포인터 이다.
va_start : va_list로 만들어진 포인터에세 가변인자 중 첫번째 주소를 가르쳐주는 매크로이다.
#define va_start(ap, v) ( (ap) = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
_ADDRESSOF(v) ⇒ &(v), 주소로 바꿔주는 매크로 이다.
_INTSIZEOF(n) => ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ), 비트 연산이 들어가는데 자세한 계산까지는 알 필요 없습니다. 마지막 고정인수의 사이즈를 구해서 그 다음 인자의 시작주소. 즉, 가변인자의 시작주소까지의 메모리상의 거리 를 구해주는 매크로이다.
va_arg : 특정 가변인자를 가리키는 va_list의 포인터를 다음 가변인자로 이동시켜 주는 매크로이다.
더한 다음 그대로 다시 빼주는 이유는 ap값을 변화시키고 변화시키지 않으며 값을 리턴해주기 위해서이다.
#define va_arg(ap,t) ( (t )((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
va_copy : va_start를 dest에 적용한 후 dest를 src의 사본으로 초기화해준다.
va_end : 사용한 가변인자 변수를 끝낼때 사용한다.
#define va_end(ap) ( ap = (va_list)0 )
클래스(구조체)에 바이트를 추가해 CPU접근에 부하를 덜어주는 기법이다.
Type | 출력 | 리턴 |
---|---|---|
%c | char 문자 출력 | 1 |
%s | 문자열 출력 | 문자열 길이 |
%d && %i | 부호있는 10진법으로 나타낸 정수 | 값의 길이 |
%u | 부호없는 10진법으로 나타낸 정수 | 값의 길이 |
%p | 포인터 주소 | 주소값의 길이 |
%X && %x | 16진법으로 나타낸 정수(대,소문자 순) | 값의 길이 |
플래그 | 설명 |
---|---|
- | 필드에서 값을 왼쪽정렬한다. |
+ | 양음수일 때 +,- 표시 |
'공백' | 양수일 때 공백, 음수일 때 - 표시 |
0 | 오른쪽 정렬일때 공백을 0으로 메꾼다. |
. | 실수일 때 소수점 이하의 자릿 수 를 결정해 준다. |
* | 서식지정자로 출력할 인수 앞에 가변인수로 필드의 폭을 결정한다. |
숫자 | 출력할 값의 폭(최소 너비)을 지정한다. |
' | 정수와 지수에 천 단위를 표시 |
% | % 출력 |
# | 진법 형식에 맞게 0, 0x, 0X를 추가 |
static int check_type(const char c, va_list *ap) // 파싱을 해주는 부분
{
/* 각 서식지정자에 대해서 예외처리를 다해주되 write함수의 오류에 따른 예외처리도 해주면 좋다. */
if (c == 'c')
return (ft_printf_c(va_arg(*ap, int)));
else if (c == 's')
return (ft_printf_s(va_arg(*ap, char *)));
else if (c == 'd' || c == 'i')
return (ft_printf_di(va_arg(*ap, int)));
else if (c == 'u')
return (ft_printf_u(va_arg(*ap, unsigned int)));
else if (c == 'x' || c == 'X')
return (ft_printf_hex(va_arg(*ap, unsigned int), c));
else if (c == 'p')
return (ft_printf_p(va_arg(*ap, void *)));
else if (c == '%')
return (ft_printf_c('%'));
return (-1);
}
int ft_printf(const char *format, ...)
{
int cnt;
int idx;
int len;
va_list ap;
va_start(ap, format);
cnt = 0;
idx = 0;
while (format[idx])
{
if (format[idx] == '%')
len = check_type(format[++idx], &ap); // 오류가 발생하는 경우를 생각해주기 위해
else
len = ft_printf_c(format[idx]);
if (len < 0) // 오류가 발생했다는 의미
return (-1);
cnt += len;
idx++;
}
va_end(ap);
return (cnt);
}
파싱이후 각 서식지정자별로 구현을 하면 된다.