본문 바로가기

42cursus

ft_printf - 초간단 정리 (42seoul)

0. 프로젝트 목표

- stdio.h 에 있는 printf와 유사한 함수 만들기

- 뉴라인버퍼를 사용하는 것은 아니고 문자열 해석해서 write함수로 찍어내기

- %[flags][width][precision][cspdixX%] 만 하기

- flag는 0과 -, specifier는 cspdixX% 만 출력하기

 

 

 

1. Makefile

1. libft.a를 이용해서 libftprintf.a를 만들어야 함

2. libft.a 를 컴파일 libftprintf.a로 복사 후 만든 .c파일을 libftprintf.a에 추가하면 됨

 -> 그렇게 하지 않으면 libftprintf.a 만 가지고 libft.a에 있는 함수를 사용할 수 없음

 -> 왜냐하면, libftprintf.a의 소스파일 중 libft.a의 함수를 사용하기 때문에..

 -> 사용하려면 -lft -lftprintf 이렇게 두개의 라이브러리를 추가해야 함

 -> 결국 테스트나, 뮬리넷은 libftprintf.a 만 가지고 결과값을 내기 때문에

 -> libft.a 에 소스를 추가해야 맞는 듯 (cp ./lib/libft.a libftprintf.a)

3. 참고로 -c로 obj까지 컴파일 할 땐 링킹과정이 없기때문에 -l 옵션은 사용되지 않음에 명심

4. I옵션으로 2개를 줘야함 libft.h파일은 ./lib에, libftprintf.h은 ./header에 있기 때문

5. 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
CC = gcc
CFLAGS = -Wall -Wextra -Werror
 
LIB_DIR = ./lib
 
INC = -I./lib -I./header
 
NAME = libftprintf.a
 
SRC_DIR = ./src
SRC_NAME = ft_printf.c
SRCS = $(addprefix $(SRC_DIR)/, $(SRC_NAME))
 
OBJ_DIR = ./obj
OBJ_NAME = $(SRC_NAME:.c=.o)
OBJS = $(addprefix $(OBJ_DIR)/, $(OBJ_NAME))
 
$(NAME) : $(OBJS)
    $(MAKE) -C $(LIB_DIR) bonus
    cp $(LIB_DIR)/libft.a $@
    ar rc $@ $^
 
$(OBJS) :
    $(CC) $(CFLAGS) $(INC) -c $(SRCS) -o $@
 
all : $(NAME)
 
clean :
    $(MAKE) -C ./lib clean
    rm -rf $(OBJS)
 
fclean :
    $(MAKE) -C ./lib fclean
    rm -rf $(NAME) $(OBJS)
 
re : fclean all
 
.PHONY : all clean fclean re
 
cs

 

 

www.cplusplus.com/reference/cstdio/printf/

 

printf - C++ Reference

function printf int printf ( const char * format, ... ); Print formatted data to stdout Writes the C string pointed by format to the standard output (stdout). If format includes format specifiers (subsequences beginning with %), the additional arg

www.cplusplus.com

2. cspdiuxX% 제어자 정리

%c : character

%s : string

%p : pointer address

%d : signed decimal integer

%i : signed decimal integer

%u : unsigned decimal integer

%x : unsigned Hex integer (lowercase)

%X : unsigned Hex integer (uppercase)

%% : print % character

 

3. - 0 . *  정리

number : 폭 크기 (default로 오른쪽 정렬, space로 채움)

- : 왼쪽 정렬

0 : 오른쪽 정렬일 때 빈칸을 space가 아닌 0으로 채움 (정수일 때 유효)

.number : 정수일 땐 출력되는 최소 숫자 (더 크면 0으로 채움), 문자열일 땐 최대 문자수

* : number를 파라미터로 받음

cf) 그냥 최대한 많은 경우를 printf에서 테스트해보고 똑같이 구현하면 됨

 

 

 

4. 가변인자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdarg.h>
 
void    foo(const char *format, ...)
{
    va_list ap; // 가변인자를 불러올 데이터리스트
    size_t    i;
 
    i = 0;
    va_start(ap, format);
    // 2번째 매개변수는 가변인자 직전의 매개변수를 넣음 (가변인자의 주소를 판단하기 위함인듯)
    {    // 사실 중괄호 {}는 필요없으나 가독성을 위함이라고 POPE...
        while (*format)    
        {
            if (*format == '%')
            {
                ++format;
                if (*format == 'c')
                {
                    char ch = va_arg(ap, int); // word단위로 스택에 들어가서 char도 int로 뽑음
                    write(1&ch, 1);
                }
                // any command
            }
            else
            {
                write(1&str[i], 1);
            }
            i++;
        }
    }
    va_end(ap); //가변인자 리스트 ap 사용을 중단함을 알림
}
cs

malbongcode.tistory.com/108?category=892906

 

[C언어] 가변인자함수(1) - 의미/사용/매크로함수/원리/예외

 

malbongcode.tistory.com

 

5. 전체적인 로직 흐름

1. while문으로 char하나씩 출력

2. %를 만났을 때는 다른 로직

  -> parsing (%[flag][width][.precision]specifier 를 구조체에 넣기) -> 넘어간 index 값 리턴

  -> make_data (모든 값을 char *로 만들기, 출력에 용이함) -> 에러체크

  -> print_data (parsing한 구조체의 값에 따라 출력하기) -> 출력한 cnt 값 리턴

 

cf) 속도적인 측면에서는 write를 줄이는 게 맞음 

cf) 생산적인 측면에서는 write로 하나씩 찍어내는 것이 맞음