42seoul:: printf 구현 및 정리

jahlee·2023년 1월 3일
0

개인 공부

목록 보기
2/23

# 구현을 함에 있어서 기본적인 서식지정자만 구현을 해 주었다.

가변 인자란?

printf(”%d %d %d”,1,2,3) 에서 인자를 몇개를 넣어도 잘 돌아간다.
printf의 프로토타입을 확인해보면 다음과 같다.

int printf(const char* format, ...)

이때 두번째 인자로 사용되는 … 이 가변인자, 혹은 가변 파라미터라고 불리는 것이다.
먼저 가변 인자 함수를 만들기 위해서는 stdarg.h 헤더파일을 포함해야한다. 이 헤더 파일에 가변인자 함수를 만들 때 필요한 각종 매크로 들이 정의되어 있다. 또한 최소 1개 이상의 고정인수 가 있어야 한다.

  1. va_list : 각 가변 인자의 시작 주소를 가리킬 포인터 이다.

  2. 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) ), 비트 연산이 들어가는데 자세한 계산까지는 알 필요 없습니다. 마지막 고정인수의 사이즈를 구해서 그 다음 인자의 시작주소. 즉, 가변인자의 시작주소까지의 메모리상의 거리 를 구해주는 매크로이다.

  3. va_arg : 특정 가변인자를 가리키는 va_list의 포인터를 다음 가변인자로 이동시켜 주는 매크로이다.
    더한 다음 그대로 다시 빼주는 이유는 ap값을 변화시키고 변화시키지 않으며 값을 리턴해주기 위해서이다.

    #define va_arg(ap,t) ( (t )((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

  4. va_copy : va_start를 dest에 적용한 후 dest를 src의 사본으로 초기화해준다.

  5. va_end : 사용한 가변인자 변수를 끝낼때 사용한다.

    #define va_end(ap) ( ap = (va_list)0 )

바이트 패딩(Byte Padding) // 참고만

클래스(구조체)에 바이트를 추가해 CPU접근에 부하를 덜어주는 기법이다.

서식지정자

Type출력리턴
%cchar 문자 출력1
%s문자열 출력문자열 길이
%d && %i부호있는 10진법으로 나타낸 정수값의 길이
%u부호없는 10진법으로 나타낸 정수값의 길이
%p포인터 주소주소값의 길이
%X && %x16진법으로 나타낸 정수(대,소문자 순)값의 길이

플래그

플래그설명
-필드에서 값을 왼쪽정렬한다.
+양음수일 때 +,- 표시
'공백'양수일 때 공백, 음수일 때 - 표시
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);
}

파싱이후 각 서식지정자별로 구현을 하면 된다.

출처 및 링크
바이트 패딩(Byte Padding)설명 링크
printf구현 참고 링크

0개의 댓글