프로그램 이름 | libftprintf.a |
---|---|
제출할 파일 | .c, /.c, .h, /.h, Makefile |
Makefile 규칙 | all, clean, fclean, re, bonus |
사용가능한외부 함수 | malloc, free, write, va_start, va_arg, va_copy, va_end |
직접 만든 libft | 사용 가능 |
설명 | 실제 printf의 동작을 모방한 ft_printf를 포함하는 라이브러리를 작성하세요. |
int ft_printf(const char *, ...);
이어야 합니다.libc
의 printf
함수를 재구현해야 합니다.printf
처럼 버퍼 관리를 수행해서는 안 됩니다.cspdiuxX%
함수에서 타입과 개수가 정해지지 않은 여러개의 인자를 받고 싶은 겨우 stdarg.h에 포함된 va_list 타입
va_arg, va_start, va_end함수를 활용한다.
1바이트 단위로 이동하기 위해서 va_list의 실제 타입은 char *로 사용되며, 이는 va_arg에서의 포인터 연산에 활용된다.
void va_start(va_list ap, var_name);
ap => va_list 로 만든 포인터가 담긴다.
var_name => 마지막 고정된 필수 인수가 담긴다.
#define va_arg(ap, t) \
(((ap) = (ap) + __va_argsiz(t)), \ // 먼저 ap 값을 밀어줌
*((t*) (void*) ((ap) - __va_argsiz(t)))) // 반환값으로 밀어주기 전의 주소에서 캐스팅 값
va_start와 va_end는 반환값이 없다.
stdarg.h에 포함된 함수와 타입의 정의는 다음과 같다.
매크로함수로 정의되어 있다
type va_arg(
va_list arg_ptr,
type
);
void va_copy(
va_list dest,
va_list src
); // (ISO C99 and later)
void va_end(
va_list arg_ptr
);
void va_start(
va_list arg_ptr,
prev_param
); // (ANSI C89 and later)
가변 인자들은 메모리 공간에 할당되어있다. 따라서 해당 가변인자를 활용하기 위해서 함수의 매개변수중 이전의 마지막 인자의 위치를 알아야한다.
성공하면 기록된 바이트 수가 반환된다.
오류가 발생되면 -1이 반환되며, enrno가 적정하게 설정된다.
https://linux.die.net/man/2/write
#include <stdio.h>
int main(void)
{
int print_return;
int ft_print_return;
print_return = printf("%d", 123123123);
printf("\n");
ft_print_return = ft_printf("%%lklHElddddd");
printf("\n");
printf("original : %d \n", print_return);
printf("my printf : %d", ft_print_return);
}
#include "ft_printf.h"
static void print_format(va_list ap, char c, int *i)
{
if (c == 'c')
ft_putchar(va_arg(ap, int), i);
else if (c == 's')
ft_putstr(va_arg(ap, char *), i);
else if (c == 'p')
ft_memory(va_arg(ap, void *), i);
else if (c == 'd' || c == 'i')
ft_putnbr_base(va_arg(ap, int), "0123456789", i);
else if (c == 'u')
ft_unsignednbr_base(va_arg(ap, unsigned int), "0123456789", i);
else if (c == 'x')
ft_unsignednbr_base(va_arg(ap, unsigned int), "0123456789abcdef", i);
else if (c == 'X')
ft_unsignednbr_base(va_arg(ap, unsigned int), "0123456789ABCDEF", i);
else if (c == '%')
ft_putchar(c, i);
else
*i = -1;
}
int ft_printf(const char *format, ...)
{
va_list ap;
int i;
va_start(ap, format);
i = 0;
while (*format)
{
if (*format == '%')
{
format++;
print_format(ap, *(format), &i);
}
else
ft_putchar(*(format), &i);
if (i == -1)
{
va_end(ap);
return (i);
}
format++;
}
va_end(ap);
return (i);
}