Unborn 8.0 Yellow Pointer
본문 바로가기
42 SEOUL/1_ft_printf

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

by 에삐니 2022. 4. 19.
728x90

 

1. 프로젝트 구조

mandatory part만 진행했으며 전체적인 구조는 아래와 같다.

📦ft_printf
 ┣ 📂includes
 ┃ ┗ 📜ft_printf.h
 ┣ 📂libft
 ┃ ┣ 📜ft_strlen.c
 ┃ ┣ 📜libft.h
 ┃ ┗ 📜Makefile
 ┣ 📂srcs
 ┃ ┣ 📜ft_checkbase.c
 ┃ ┣ 📜ft_formats.c
 ┃ ┣ 📜ft_printbase.c
 ┃ ┣ 📜ft_printf.c
 ┃ ┗ 📜ft_printstr.c
 ┣ 📜Makefile

 

2. 프로젝트 구현

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

- 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

- ft_printf.c

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

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);
}

- ft_formats.c

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

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_checkbase.c

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

- ft_printbase.c

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

- ft_printstr.c

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

- Makefile

  • Makefile은 '변수명 = 값'으로 변수를 선언 후 값을 저장해서 사용할 수 있다. 이후 변수를 사용할 때는 $(변수명)처럼 이용해서 사용한다.
  • $@ : 현재의 타겟명
  • $^ : 현재 타겟의 의존성
  • $? : 현재의 목표 파일보다 더 최근에 갱신된 파일 이름
  • $< : 현재의 목표 파일보다 더 최근에 갱신된 파일 이름
  • .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

 

3. 사용한 테스터

https://github.com/chronikum/printf42_mandatorytester

https://github.com/Tripouille/printfTester

728x90
반응형

댓글