42Seoul

[42Seoul][Printf] ft_printf - mandatory part [C]

목차
ft_printf
mandatory part
-가변인자
-서식지정자
-구현코드

Ft_printf mandatory part

 

보통 printf 함수를 사용할 때 앞부분은 출력할 서식지정자를 넣어주고 뒷 부분에 출력할 값을 넣어줍니다.

 

이 부분을 직접 구현하기 위해 stdarg 헤더에 있는 가변인자 관련 매크로를 사용합니다.

 

가변인자

가변인자 함수 사용에 대한 글

https://jhnyang.tistory.com/293

 

[C,C++] 가변인자 함수의 사용(va_start, va_arg, va_list등등) 함수에 불특정 여러개의 인자를 넘기고 싶

[C, C++ 프로그래밍 강좌 목차] 안녕하세요~ 양햄찌 주인장입니다. 오늘은 오랜만에 프로그래밍 언어에 관련된 포스팅을 들고왔어요. 오늘의 주제 포스팅을 들어가기 전 'C++의 오버로딩'에 대한

jhnyang.tistory.com

printf("%d", 1);

뒷 부분이 가변인자 인데, 이 목록을 담기 위해 va_list 를 사용합니다

printf("%d %d %d", 1, 2, 3);

 

va_arg 는 va_list 에 있는 뒷 부분의 값이 어떤 타입형태로 반환되게끔 합니다.

8진수이건 16진수이건 정수형태이건, va_arg(*ap, int); va_arg(*ap, unsigned int); 등으로 나타납니다.

해당 포인터로 va_list 에 있는 값에 접근 하여 매개변수로 넣어준 타입으로 반환합니다.

 

서식지정자

%c, %d, %i, %u, %x, %X, %p, %s

 

%c 정수를 문자로 해석

%d 부호 있는 10진수 정수로 해석

%i 부호 있는 10진수 정수로 해석

%u 부호 없는 10진수 정수로 해석

%x 부호 없는 16진수 정수로 해석(소문자)

%X 부호 없는 16진수 정수로 해석(대문자)

%p 포인터가 참조하고 있는 메모리의 주소값(8자리의 16진수) 

%s 정수를 문자열로 해석

 

참고 자료

https://bigpel66.oopy.io/library/42/inner-circle/4

 

ft_printf

Subjects

bigpel66.oopy.io

 

구현 코드

 메인 로직을 보면 서식지정자가 담긴 포인터 format 을 가변인자 목록을 불러와(va_list) 해당 목록에 ap 포인터로 접근하여 인자를 담고(va_start) 그 인자에 하나하나 접근하여 해당 서식지정자에 맞게 va_arg를 사용하여 해당 서식지정자에 맞는 타입을 반환합니다. va_list 에 담겨있는 여러 값들을 ap 포인터로 va_arg 로 접근할 수 있어, 해당 서식지정자에 맞게 출력합니다.

 해당 format 이 맞는지 format_checker 로 각각의 서식지정자에 맞게 맞춰 출력합니다.

#include "ft_printf.h"

int	ft_putchar(char c)
{
	int	len;

	len = write(1, &c, 1);
	return (len);
}

int	format_checker(char c, va_list *ap)
{
	int	len;

	len = 0;
	if (c == 'c')
		len += ft_putchar(va_arg(*ap, int));
	else if (c == '%')
		len += write(1, "%", 1);
	else if (c == 'd' || c == 'i')
		len += ft_putnbr(va_arg(*ap, int));
	else if (c == 'u')
		len += ft_putunbr(va_arg(*ap, unsigned int));
	else if (c == 'x')
		len += ft_puthex(va_arg(*ap, unsigned int), 1);
	else if (c == 'X')
		len += ft_puthex(va_arg(*ap, unsigned int), 2);
	else if (c == 'p')
	{
		len += write(1, "0x", 2);
		len += ft_putadr(va_arg(*ap, unsigned long int));
	}
	else if (c == 's')
		len += ft_putstr(va_arg(*ap, char *));
	return (len);
}

int	ft_printf(const char *format, ...)
{
	va_list	ap;
	int		len;
	int		i;

	len = 0;
	i = 0;
	va_start(ap, format);
	while (format[i])
	{
		if (format[i] != '%')
			len += write(1, &format[i], 1);
		else
		{
			len += format_checker(format[i + 1], &ap);
			i++;
		}
		i++;
	}
	va_end(ap);
	return (len);
}

 

 각각의 서식지정자에 맞게 출력함수들을 구현했습니다. format_checker 로 넘어온 값을 아래 함수들로 각각에 맞게 출력하게끔 분기해줍니다.

#include "ft_printf.h"

int	ft_putnbr(int nb)
{
	long long	n;
	int			len;

	n = nb;
	len = 0;
	if (n < 0)
	{
		len += write(1, "-", 1);
		n *= -1;
	}
	if (n >= 10)
	{
		len += ft_putnbr(n / 10);
		len += ft_putnbr(n % 10);
	}
	else
		len += ft_putchar(n + 48);
	return (len);
}

int	ft_putadr(unsigned long int nb)
{
	int	len;

	len = 0;
	if (nb >= 16)
	{
		len += ft_putadr(nb / 16);
		len += ft_putadr(nb % 16);
	}
	else
	{
		if (nb < 10)
			len += ft_putchar(nb + 48);
		else
			len += ft_putchar(nb + 87);
	}
	return (len);
}

int	ft_putunbr(unsigned int nb)
{
	int	len;

	len = 0;
	if (nb >= 10)
	{
		len += ft_putunbr(nb / 10);
		len += ft_putunbr(nb % 10);
	}
	else
		len += ft_putchar(nb + 48);
	return (len);
}

int	ft_puthex(unsigned int nb, int s)
{
	int	len;

	len = 0;
	if (nb >= 16)
	{
		len += ft_puthex(nb / 16, s);
		len += ft_puthex(nb % 16, s);
	}
	else
	{
		if (nb < 10)
			len += ft_putchar(nb + 48);
		else
		{
			if (s == 1)
				len += ft_putchar(nb + 87);
			else
				len += ft_putchar(nb + 55);
		}
	}
	return (len);
}

int	ft_putstr(char *str)
{
	int	len;

	len = 0;
	if (!str)
		str = "(null)";
	while (*str)
		len += write(1, str++, 1);
	return (len);
}

 

 


 

 

'42Seoul' 카테고리의 다른 글

[42Seoul][GetNextLine] Get Next Line - mandatory part [C]  (0) 2022.05.22