728x90
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와 동일)
알아두어야 할 것들
함수구현의 기본 로직
- 일반 문자열 및 %% 문자열 해결
- 헤더파일에 구조체 요소들을 저장하고 초기화
- 출력 구문(%)만나면 포맷에 맞게 구조체 변수에 값을 저장
- 저장된 구조체를 바탕으로 가변인자 출력
출력구문
- buf와 ret으로 구분
- ret은 서식지정자에 맞는 가변인자 출력 문자열
- ret에 우선적으로 precise를 적용시키고 strjoin
- width와 ret의 계산을 통해 알맞는 buf를 생성하고 플래그에 따라 공백 또는 '0'을 채운다.
- '-'플래그에 맞게 순서 맞춰서 출력
- 출력한 길이를 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 - 출력 문자열의 길이
- 반환부
- 가변인자와 문자열을 출력부에 전달
- 출력되는 문자수를 반환
- 출력(일반)
- %% 중복과 일반문자열을 출력
- 전처리(%)
- %와 서식지정자까지의 옵션(box)을 저장(% 다음부터 서식지정자까지)
- 구조체를 초기화하고 box를 전달해서 구조체에 설정된 옵션들을 변경 저장
- 출력(%)
- '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 |