파도가 칠 때는 서핑을

Soon as possible

Wait!

공부/42Seoul

[1 Circle] ft_printf 정리

hyeonhki 2021. 3. 18. 11:45
728x90

ft_printf 정리

https://github.com/hyeonhki/ft_printf

- 문제 설명

  • 프로토 타입 :
  • int ft_printf(const char *format, ...);
  • format은 서식 문자열이며, ...은 생략기호로 인수 갯수, 타입을 점검하지 않도록 한다.
  • printf 함수 구현
  • cspdiuxX%의 서식지정자들을 구현

- 용어 및 문제 추가 설명

__ ✓ 가변함수(External functs.)__ #include <stdarg.h>

  • va_start : 가변인자를 va_list로부터 가져올 수 있도록 포인터를 설정
  • va_arg : 자료형의 크기만큼 가변인자 목록 포인터에서 값을 가져옴
  • va_copy :
  • va_end : 가변인자 처리가 끝났을 때 포인터를 NULL로 초기화

✓ Pirntf 옵션

  • %flag/width/.precision/type

+ flags

  • 출력 값 앞에 표시할 문자를 설정하는 영역
  • 생략 가능
  • 여러 flag 동시 사용 가능 (- > 0)
  • 보너스
  • + : 인수가 양수거나 0일때 + 부호를 출력
  • - : 왼쪽 정렬
  • 0 : 오른쪽 정렬일 때, 공백을 0으로 채움
  • # : 진수 표현
  • * : 출력너비를 인자로받아서 출력

+ width

  • 출력할 값의 최소 너비를 지정
  • 출력할 값이 지정할 너비보다 작으면 자릿수를 맞추기 위해 공백 또는 0을 채워넣는다.
  • 출력할 값이 너비보다 클 경우, 값이 잘리는 일은 있을 수 없으므로 width 옵션은 무시됨
  • * 플래그의 영향을 받으며, 음수값을 입력받을 수 있고 - 플래그가 적용된다.

+ width 예시

printf("[%4d]\n", 123); // [ 123]
// width = 4, 값은 오른쪽 정렬되고 남은 너비를 공백으로 채워서 출력
printf("[%04d]\n", 123); // [0123]
// flag = '0', width = 4, 값은 오른쪽 정렬되고, 남은 너비에 0을 채워서 출력
printf("[%-4d]\n", 123); // [123 ]
// flag = '-', width = 4, 값은 왼쪽 정렬되고 남은 너비에 공백을 채워서 출력

+ precision

  • 출력할 값의 정확도를 위한 최대 자릿수를 설정
  • 출력할 값이 정수라면 최대 자릿수를 맞추기 위해 0을 추가
  • 자릿수가 출력할 값보다 작을 경우, 값을 자르거나 하지 않고 값을 모두 출력
  • 출력할 값이 실수라면 소수점 이하의 최대 자릿수를 가리키고, 자릿수에 따라 반올림이 되거나 소수점 이하에 0이 추가됨
  • 실수 전체의 자릿수 설정은 width 옵션을 사용
  • *플래그의 적용을 받으며, .뒤에 위치하게 된다. 음수 입력시 영향받지 않는다.

+ precision 예시

printf("[%013.6f]\n", 123.456); // [000123.456000]
// flag = '0', width = 13, precision = 6
// 소수점을 6째 자리까지 출력하며 소수점 이하 0추가, 남은 너비에 0을 넣어서 오른쪽 정렬

type

  • 숫자(number), 문자(character), 문자열(string) 중의 하나
  • 숫자는 정수와 실수로 나뉘며, 정수는 다시 부호의 유무로 나뉨
  • 정수는 8,10,16진수 형태로 출력 가능
  • 실수는 일반적인 표기법 이외에 지수(exponent) 표기법으로 출력 가능
  • 타입 문자
    • %u : 10진수로 2바이트 출력/부호 없는 정수
    • %d : 10진수로 2바이트 출력/부호 있는 정수
    • %o : 8진수로 2바이트 출력/부호 없는 8진수 정수
    • %x : 16진수로 2바이트 출력. 부호 없는 16진수 정수(소문자)
    • %X : 16진수로 2바이트 출력. 부호 없는 16진수 정수(대문자)
    • %c : 단일문자 1바이트 출력
      • 0플래그 Warning, - 플래그 적용됨, * 플래그 적용됨
      • width 영향 받음
      • precision Warning
    • %s : 문자열 출력
    • %p : 포인터의 메모리주소
    • %i : 부호있는 10/8/16진수 (%d와 동일)

알아두어야 할 것들

함수구현의 기본 로직

  1. 일반 문자열 및 %% 문자열 해결
  2. 헤더파일에 구조체 요소들을 저장하고 초기화
  3. 출력 구문(%)만나면 포맷에 맞게 구조체 변수에 값을 저장
  4. 저장된 구조체를 바탕으로 가변인자 출력

출력구문

  1. buf와 ret으로 구분
  2. ret은 서식지정자에 맞는 가변인자 출력 문자열
  3. ret에 우선적으로 precise를 적용시키고 strjoin
  4. width와 ret의 계산을 통해 알맞는 buf를 생성하고 플래그에 따라 공백 또는 '0'을 채운다.
  5. '-'플래그에 맞게 순서 맞춰서 출력
  6. 출력한 길이를 return

테스터기

  • printf_lover
  • pft_2019
    • %s warning case라서 패스
  • 42printftester
    • fsanitize를 통해서 메모리 누수도 잡는 테스터기
    • 어딘가에서 동적할당을 잘못해서 나는 에러 => 구현 다시해보면서 함수 다시보고 수정했다. 주로 널 처리, 이중 프리, 말록 후 프리 안하는 등의 문제로 많이 잡혔다.
  • pft
    • %p warning case라서 패스 => pft_2019와 상충하며, pft_2019 케이스는 warning이 아니라서 변제함
    • %o 와 , '% '으로 생기는 문제

플래그

  • 0
  • +
  • *
    • width자리에 음수로 올 경우, - 플래그를 적용한다.
    • precise. 즉, . 후에 올 경우 precise에 적용

precise

  • 가변인자의 출력되는 문자열의 길이와 비교하여 precise가 더 커야 적용된다.
  • 음수값은 처리되지 않는다.
  • *로 음수를 입력받을 경우는 음수로 저장되지만, 그냥 입력이 없는 경우 0으로 기록되는 구조 지금은 아마도?

구현 Logic

precise => 출력되는 문자열에 적용
width => 전체 width - 출력 문자열의 길이

  1. 반환부
    • 가변인자와 문자열을 출력부에 전달
    • 출력되는 문자수를 반환
  2. 출력(일반)
    • %% 중복과 일반문자열을 출력
  3. 전처리(%)
    • %와 서식지정자까지의 옵션(box)을 저장(% 다음부터 서식지정자까지)
    • 구조체를 초기화하고 box를 전달해서 구조체에 설정된 옵션들을 변경 저장
  4. 출력(%)
    • 'csdiupxX' 케이스 별 출력

utils(ft)

: 프로젝트를 위한 추가적으로 만든 functions

  • ft_multifree

    • norm을 위해 어쩔 수 없이 free 2개하는 함수를 만들었다.
  • ft_dup_options(문자열, 고려하는 서식지정자, 인덱스)

    • % 이후의 문자열을 받아서 서식지정자까지를 dup해서 반환
  • ft_minus_malloc

    • 로직 상 음수로 동적할당을 하게되는 경우가 많은데 그경우 빈문자열을 할당하고 반환하도록 만들어둔 함수다.
  • ft_bewhat(void *ptr, 사이즈, 문자)

    • buf에 공백 및 0 넣어서 출력하기 위함
    • ft_bezero 변형
    • 사이즈만큼 문자로 다 통일
    • 사이즈가 0이하면 함수 종료(널) => 후에 width와 가변인자 문자열 길이 계산시 음수가 들어오는 것 때문
  • ft_bufwhat(int size, int what)

    • calloc 변형이었음
    • what을 채워서 동적할당

print_funcitons(pt)

: %이후의 출력을 담당하는 함수들

  • pt_normal
    • 서식지정자 없는 일반문자열 출력
  • pt_double
    • %%와 같이 연달아 나올 때 %만 출력
  • pt_flagswap(플래그, 문자열1, 문자열 2)
    • 플래그가 1이냐 0이냐에 따라서 문자열의 순서를 뒤바꾸어 출력
  • pt_buf
    • % 서식지정자가 들어오는 경우를 해결하기 위한 함수로 %이후 서식지정자없이 플래그들이 들어오는 경우 해당

  • pt_c
  • pt_s
  • pt_x
  • pt_X

  • pt_plusd
  • pt_minusd
  • pt_i
  • pt_u
  • pt_p

info

: 구조체에 옵션을 저장하기 위한 함수들

  • info_check_flag
    • 구조체에 플래그를 저장하기 위한 함수
  • info_check_init
    • strchr과 동일
  • info_init
    • 구조체 초기화
  • save_info
    • box(문자열)를 전달받아 구조체에 저장

변경된 라이브러리

  • ft_strlen 등 널처리에 관한 조건들을 많이 변경했음.

주의사항

  • '%023%'와 같이 정상적인 서식지정자 없이 다시 %가 올 경우를 고려할 것
    • ft_dup_options에서 %가 들어와도 box에 내용을 복사할 수 있게했고 출력부로 넘어가서 조건문에 '%'서식지정자가 없으니 0으로 리턴하게 된다.
  • 플래그의 중첩
    • -플래그와 0플래그 간의 우선순위 : - > 0
  • *로 들어온 -플래그는 기존에 있던 -플래그에게 영향을 주지 않는다.
  • %c
  • 적용받는 플래그 : -*
  • width를 통한 버퍼와 문자(c) 출력
  • '-' flag에 따라 순서를 달리하여 출력한다.
  • 다른 구현부와 다르게 buf와 ret 구분 없이 한 곳에 출력하였다. => 시간되면 동일하게 변경할 것

%s

  • 적용받는 플래그 : -*
  • 널이 들어올 경우 "(null)" 출력되어야 한다.

%d, %i

  • 적용받는 플래그 : -0*
  • 음수일 때 플래그에 따라 구현이 달라져서 양수(pt_plusd)와 음수(pt_minusd)로 구분하여 구현
  • 가변인자값과 입력되는 precise가 0이면 아무것도 출력되지 않아야한다.
  • 음수일 경우
    • width ' ' 일 경우, 숫자에 붙어서 출력
    • precise 일 경우, 맨 앞으로 출력
    • width가 짧아서 buf가 할당되지 못하면 ft_strjoin을 통한 "-" 붙이기를 할 수 없어서 '-'가 출력이 되지 않는다.
      => if(!(malloc))을 통해 음수가 들어올 경우 ft_strdup을 통해 빈문자열을 할당했다.

%u

  • 적용받는 플래그 : -0*
  • unsinged int의 출력

%p

  • "0x"와 플래그들의 관계를 잘 고려하여 출력해야한다
  • precise가 존재할 경우 0x뒤로 영향을 받으며, '0' 플래그는 적용받지 않는다.
  • putnbr_base를 이용

%xX

프로젝트를 마치고..

  • 라이브러리의 함수를 마음대로 수정하고 있는데 기록을 남겨둘 것.
  • 꼼꼼하게 기록할 것. 그날 왜 이런 함수를 추가했고 어떤 조건을 붙였는 지 시간이 지나니 이유를 알 수 없어 시간을 낭비했다.
  • 시작부터 메모리의 할당 해제와 널처리 등 메모리 누수와 힙영역 관련한 에러를 남기지 말 것
  • 코드의 범용성을 염두해두고 함수를 작성할 것
728x90

'공부 > 42Seoul' 카테고리의 다른 글

[2 Circle] ft_server 개념부터 구현까지  (0) 2021.03.30
[1 Circle] get next line 설명 및 해결  (0) 2021.03.17
[1 Circle] netwhat  (0) 2021.03.05
[0 Circle] Libft  (0) 2021.03.05