printf에 관한 마지막 포스트가 될 것이다.

해당 포스트를 읽기 전에 아래 주소에서 정리해두신 글을 한번 정독하시길 권한다.

https://watermelonlike.tistory.com/44

 

처음에는 구체적인 코드를 어떻게 짰는지에 대해 포스팅하려고 하다가,

그럴 바에 차라리 github에 나와 있는 여러 코드를 보는 게 낫겠다 싶었다.

 

그래서 본편에서는 의사코드(pseudo-code)를 통해 ft_pritnf를 어떻게 전개해나가야 할지에 대한 감을 잡게끔 도와주려 한다.

참고로 github.com/rchallie/ft_printf 의 printf가 가장 이해하기 편해 해당 코드를 참조했다.


 

수도코드(Pseudo - code)

미리 알아둘 것

-

t_flags

{

        int type;

        int width;

        int minus;

        int zero;

        int dot;

        int star;

}

메인함수 - ft_printf(const char *str, …)

 

const char *str 인자로 받음

필요한 필드 선언

        str 임시로 저장할 const char *save 선언

        va_list args 선언

        int char_count 선언

save input strdup

char_count 0으로 초기화

va_start시킴(va_start(args, input))

char_count ft_treat_save 함수의 리턴 넣음. (함수 인자는 save, args)

        ft_treat_save const char *save va_list args 받아 save 문자열의 끝에 도달할 때까지 함수들을 적용.

va_end(args) 해줌.

인자로 받아온 (char*) save free 시켜줌

char_count 리턴.

 

ft_treat_save(const char *save, va_list args)

 

필요한 필드 선언

        int i;

        t_flags flags;

        int char_count;

필드 초기화

        i = 0;

        char_count = 0;

while (1)

        flags ft_init_flags() 리턴값을 담음.

        if save[i] 문자를 만나면

               break;

        else if save[i] 번째가 '%' 이면서 save[i + 1] 번째가 문자가 아니면

            플래그 자리수 만큼 i 더함.(최소 1 더해서 %다음 글자를 가리키게 만듬)

            (== i ft_flag_parse(save, ++i, &flags, args) 리턴값을 담음.)

            if save[i] `cspdiuxX%` 안에 있다면

                    char_count save[i] 해당하는 글자와 관련된 함수를 적용해 리턴값을 더함.

                   ( 경우 save[i] 해당하는 글자는 cspdiuxX%)

                   (관련 함수는 혼자서 생각해보기. Atoi, atoi_base 등을 이용하면 .)

                    (char_count ft_treatment((char)flags.type, flags, args) 결과값을 더함.)

            else if save[i] '%' 아닌 경우( 일반적인 경우)

                    char_count 1 더함.

                   ft_putchar(save[i])

        end if    

        i++

end while

char_count를 리턴

 

t_flags ft_init_flags()

flags 값들을 초기화

        flags dot -1 초기화

        flags minus, star, type, width, zero 0으로 초기화

flags 리턴.

 

 

ft_flag_parse(const char *save, int i, t_flags *flags, va_list args)

while save[i] 문자('\0') 만나지 않을 때까지

          if save[i] 숫자가 아님 && save[i] `cspdiuxX%` 하나가 아님 && flag(-0. *) 아님

                   break;

            end if

           if save[i] 문자 '0' 같음 && flags->width 0 && flags->minus 0

                  flags->zero 1 초기화

            end if

            if save[i] `.` 같음

                   `.` 뒤에 나오는 `*` 또는 숫자 개수 만큼 i 이동시킴(더함.)

                    (i ft_flag_dot(save, i, flags, args) 리턴값을 담음.)

            end if

            if save[i] `-` 같음

                  *flags minus 1 설정하고 width -1 곱함.

                  (ft_flag_minus(*flags) 결과를 적용)

                   (여기서의 * 포인터가 아니라, 인자로 받은 *flags 안에 있는 .)

           end if

           if save[i] `*` 같음.

           *flags 다음의 리턴 값을 담음 : ft_flag_width(args, *flags)

            end if

           if save[i] 숫자면(ft_isdigit(save[i]))

                   flags star 1이면 width 0으로 만들고 .뒤에 나오는 숫자(하나) 담음.

                    (*flags ft_flag_digit 결과를 담음.)

           end if

           if save[i] `cspiduxX%` 하나라면

           (== ft_is_in_type_list(save[i]))

                 flags type save[i] 담음.

            i 1 더함

            end while

return i

int ft_flag_dot(const char *save, int start, t_flags *flags, va_list args)

 

i필드를 선언하고, start + 1 초기화

if save[i] * 이면

        flags->dot va_arg(args, int) 담음.

       i 1 증가.

else

        flags->dot 0 담음.

        while save[i] 숫자인 동안

               flags->dot '.'뒤의 숫자를 담음.

                (== flags->dot * 10 + save[i++] - '0')

       end while

i 리턴

 

t_flags ft_flag_minus(t_flags flags)

 

flags minus 1 설정

flags width -1 곱함.

flags 리턴

 

 

t_flags ft_flag_width(va_list args, t_flags flags)

 

flags star 1 담음

flags width va_arg(args, int) 결과를 담음.

if flags width 0보다 작으면

        flags minus 1 담음

        flags width -1 곱함.

end if

flags 리턴

 

t_flags ft_flag_digit(char c, t_flags flags)

 

if flags star 1이면

       flags width 0 담음.

flags width (flags.width * 10) + (c - '0') 담음.

(== atoi 처럼 .뒤에 나오는 숫자를 담는 .)

return flags

 

 

int ft_treatment(int c, t_flags flags, va_list args)

필드 설정 초기화 

        int char_count 선언. 0으로 초기화    

글자에 맞는 함수들을 적용

        If (c == ‘c’)

                char_count char 다루는 함수를 적용.

                (== ft_treat_char(va_arg(args, int), flags) 리턴값을 담음) 

       Else if (c == ’s’)

               char_count char * 다루는 함수 적용

        이런식으로

       P, d 또는 i, u, x, X, % 다룸.

char_count 리턴.

 

 

int ft_treat_char(char c, t_flags flags)

리턴할 필드 설정.(int char_count)

If flags minus 1이면( == flags `-` 있으면)

       ft_putchar c 출력

End if

width만큼 `0`이나 ` ` 출력한 출력한 개수 만큼 char_count 담음.

(char_count ft_treat_width(flags.width, 1, 0) 결과값을 담음.)

If flags minus 0이면

        c 출력.

char_count 1 더한 값을 리턴.

(1 더하는 이유는 width뿐만 아니라 c하나도 출력해야 하기 때문)

 

 

 

 

int ft_treat_width(int width, int minus, int has_zero)

int char_count 필드를 선언하고 0으로 초기화

While width - minus 0보다 동안

        if has_zero 0 아니면(true이면)

                ‘0’ 출력

       else

              ‘ ‘ 출력

        width에서 1

        char_count 1 더함

End while

char_count 리턴. 

 

import

 

#include <stdarg.h>

#include <unistd.h>

 

 

참고 - 문자마다 어떤 함수를 적용할지

 

['c'] = &ft_formatcha

['s'] = &ft_formatstring

['d'] = &ft_formatdecimal

['i'] = &ft_formatdecimal

['o'] = &ft_format_octal

['p'] = &ft_formatpointer

['X'] = &ft_format_upphex

['x'] = &ft_format_lowhex

['u'] = &ft_format_unsigneddecimal

['f'] = &ft_format_floats

 

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기
// custom