[42-Seoul/ft_printf] 프로젝트 구현

yebeen·2022년 5월 20일
0

42-Seoul/ft_printf

목록 보기
3/3
post-thumbnail

libft

libft 사용함수는 ft_strlen만을 사용했으며 함수에 맞게 libft.h와 Makefile을 수정했다.

  • ft_strlen.c
  • libft.h
  • Makefile

include

해당 폴더에는 해더 파일이 들어있다.

  • ft_printf.h
#ifndef FT_PRINTF_H 
# define FT_PRINTF_H 

# include <stdarg.h> 
# include <unistd.h> 
# include "../libft/libft.h" 

int ft_printf(const char *str, ...); 

int ft_parsing(va_list args, const char format); 
int ft_formats(va_list ap, const char *format); 

char *base_type(const char type); 
int ft_checkbase(va_list ap, const char format); 

int ft_printi(int n, const char *base); 
int ft_printu(unsigned int n, const char *base); 
int ft_printp(unsigned long long n, const char *base); 
void ft_printbase(unsigned long long num, const char *base); 

int ft_printchar(int chr); 
int ft_printstr(char *str); 

#endif

srcs

해당 폴더에는 소스 파일들이 들어있다.

  • ft_printf.c
int ft_printf(const char *format, ...) { 
    va_list args; 
    int print_length; 

    va_start(args, format); 
    print_length = ft_formats(args, format); 
    va_end(args); 
    return (print_length); 
}

해당 함수에서는 입력을 받고 결과를 return하는 기능으로 구현했다. va_list 가변 인자 포인터 변수를 args라는 이름으로 선언하고, va_start(args, format)을 이용해 가변 인자를 가리키게 했다.


  • ft_formats.c
int ft_parsing(va_list args, const char format) {
    int print_length; 
    print_length = 0; 
    if (format == '%') 
        print_length += write(1, "%", 1); 
    else if (format == 'c') 
        print_length += ft_printchar(va_arg(args, int)); 
    else if (format == 's') 
        print_length += ft_printstr(va_arg(args, char *)); 
    else print_length += ft_checkbase(args, format); 
    return (print_length); 
} 

int ft_formats(va_list ap, const char *format) { 
    int i; 
    int print_length; 
    i = 0; print_length = 0; 
    while (format[i]) { 
        if (format[i] == '%') { 
            print_length += ft_parsing(ap, format[i + 1]); i++; 
        } 
        else 
            print_length += write(1, (format + i), 1); i++; 
    } 
    return (print_length);
}

이후 ft_fotmats에서 ft_parsing 함수를 이용해 문자열을 파싱하고 문자열의 수를 반환하도록 했다.


  • ft_checkbase.c
char	*base_type(const char type)
{
    if (type == 'u' || type == 'd' || type == 'i')
        return ("0123456789");
    else if (type == 'x' || type == 'p')
        return ("0123456789abcdef");
    else if (type == 'X')
        return ("0123456789ABCDEF");
    return (0);
}

int	ft_checkbase(va_list ap, const char format)
{
    int		print_length;
    char	*base;

    base = base_type(format);
    print_length = 0;
    if (format == 'd' || format == 'i')
        print_length += ft_printi(va_arg(ap, int), base);
    else if (format == 'u' || format == 'x' || format == 'X')
        print_length += ft_printu(va_arg(ap, unsigned int), base);
    else if (format == 'p')
        print_length += ft_printp(va_arg(ap, unsigned long long), base);
    return (print_length);
}

ft_checkbase에서 서식지정자에 맞는 베이스를 찾을 수 있도록 해주었다. 그 후 서식지정자에 맞게 d, i, u, x, X, p에 따라 출력할 수 있도록 ft_printbase를 해준다.


  • ft_pirntbase.c
void	ft_printbase(unsigned long long num, const char *base)
{
    size_t	len;

    len = ft_strlen(base);
    if (num >= len)
    {
        ft_printbase(num / len, base);
        ft_printbase(num % len, base);
    }
    else
    {
        write(1, &base[num % len], 1);
    }
}

int	ft_printi(int n, const char *base)
{
    int		print_length;

    print_length = 0;
    if (n == -2147483648)
    {
        print_length += write(1, "-2147483648", 11);
        return (print_length);
    }
    if (n < 0)
    {
        print_length += write(1, "-", 1);
        n = -n;
    }
    if (n == 0)
        print_length += write(1, "0", 1);
    else
        ft_printbase(n, base);
    while (n)
    {
        print_length += 1;
        n /= 10;
    }
    return (print_length);
}

int	ft_printu(unsigned int n, const char *base)
{
    size_t	base_len;
    int		print_length;

    print_length = 0;
    base_len = ft_strlen(base);
    if (n == 0)
        print_length += write(1, "0", 1);
    else
        ft_printbase(n, base);
    while (n)
    {
        print_length += 1;
        n /= base_len;
    }
    return (print_length);
}

int	ft_printp(unsigned long long n, const char *base)
{
    int					print_length;

    print_length = 0;
    print_length += write(1, "0x", 2);
    if (n == 0)
        print_length += write(1, "0", 1);
    else
        ft_printbase(n, base);
    while (n)
    {
        print_length += 1;
        n /= 16;
    }
    return (print_length);
}

write() 함수를 써서 출력하고 길이를 반환하는 기능을 한다.


  • ft_printstr.c
	int	ft_printchar(int chr)
	{
		unsigned char	c;

		c = (unsigned char)chr;
		write(1, &c, 1);
		return (1);
	}
	
	int	ft_printstr(char *str)
	{
		int	print_length;

		if (!str)
		{
			print_length = write(1, "(null)", 6);
			return (print_length);
		}
		print_length = write(1, str, ft_strlen(str));
		return (print_length);
	}

서식지정자 c와 s의 출력을 처리하는 부분이다. 서식지정자 s의 경우, NULL값을 때 (null)이 출력되도록 하고 반환 값은 6으로 처리해주었다.


  • Makefile
    Makefile은 '변수명 = 값'으로 변수를 선언 후 값을 저장해서 사용할 수 있다. 이후 변수를 사용할 때는 $(변수명)처럼 이용해서 사용한다.

    "변수명 설명"
    $a : 현재의 타겟명
    $^ : 현재 타겟의 의존성
    $? : 현재의 목표 파일보다 더 최근에 갱신된 파일 이름
    $< : 현재의 목표 파일보다 더 최근에 갱신된 파일 이름
    .PHONY: 실행 규칙을 위한 타겟명으로 사용하기 위한 것으로 타겟명으로 
    		사용하는 단어가 파일명으로 있을 경우 충돌이 발생하는데, 
    		이때 .PHONY에 타겟명을 명시하게되면 프로그램이 정상적으로 동작하게 된다.
    @ : 명령어와 명령의 실행 결과를 출력하지 않는다.
    -C dir : dir로 우선 이동할 수 있게된다. 순환 make에서 사용하게 된다.
NAME		= libftprintf.a

CC			= gcc
CFLAGS		= -Wall -Wextra -Werror

AR			= ar
ARFLAGS		= rcs

RM			= rm -rf

INCDIR		= ./includes
LIBFT		= ./libft

SRCS		= ./srcs/ft_printf.c	\
			  ./srcs/ft_formats.c	\
			  ./srcs/ft_checkbase.c	\
			  ./srcs/ft_printbase.c	\
			  ./srcs/ft_printstr.c	\

OBJS 		= $(SRCS:.c=.o)

%.o : %.c
	$(CC) $(CFLAGS) -c $< -o $@

$(NAME) : $(OBJS)
	@make -C $(LIBFT)
	@cp $(LIBFT)/libft.a $(NAME)
	@ar rcs $@ $?

all : $(NAME)

clean : 
	$(RM) $(OBJS)
	@make clean -C $(LIBFT)

fclean : clean
	$(RM) $(NAME)
	@make fclean -C $(LIBFT)

re:	clean all

.PHONY: all clean fclean re
profile
🐣🐥

0개의 댓글