Search
moon
sun

Solution

1. 필수개념

printf 란?

•
처음 c언어를 배울때 출력방법중 하나로 알게되는 그 printf 맞다
•
일반 문자열에 %들을 통해서 문자열을 구성하여 출력한다.
int printf(const char *format, ...);
C++
복사
•
인자
◦
출력할 문자열
◦
%에 해당되는 변수들
•
반환값
◦
출력된 문자열 갯수
•
예시
int num = 5; ret = printf("Num:%d\n", num);
C++
복사
◦
실제 출력 : Num:5$ ($는 엔터)
◦
% 뒤에 붙어있는 d 같은 애들을 서식지정자라고 부른다.
◦
이떄 ret 의 값은 6 이다. (엔터 포함)
•
서식지정자
◦
서식지정자에는 아래와 같은 규칙들이 존재한다.
%[flags][width][.precision][length]type
C++
복사
◦
아래 로직 부분에서 하나씩 알아보면서 직접 구현해본다.
◦
[ ] 는 옵션이고 % 와 type 은 필수로 들어가야한다.

가변인자

•
위의 프로토타입을 보면 두번째 인자가 ... 인것을 알수있다.
•
앞의 문자열에 있는 형식의 갯수에 따라서 인자의 갯수가 달라지기 때문에 가변인자를 쓴다.
•
자세한 설명과 사용방법은 여기를 참고하자

2. 테스트

3. 로직

•
flag, width, precision 규칙은 이미 다른분들이 잘 정리했기 때문에 생략하고,
•
규칙에 맞게 잘 구현하는 방법을 적었습니다.
•
기본로직은 파싱 → 포장 → 출력 으로 이루어져 있습니다.
•
% 가 나올떄까지는 그대로 출력하고
•
% 가 나오기 시작한 부분부터 아래의 로직을 구현하면 됩니다.
•
구체적인 코드는 여기를 확인해주세요.

3-1. 파싱

•
% 가 나오면 파싱을 시작합니다.
•
다음와같이 flag, width, precison, type 을 파싱해야합니다.
%[flags][width][.precision]type
C++
복사
•
파싱한 결과값을 저장할 구조체를 선언해줍니다.
typedef struct s_flag { int flag; int width; int precision; int type; } t_flag;
C++
복사
•
서식 지정자는 순서대로 들어옵니다.
◦
위의 형식을 지키지 않은 입력은 오류로 냅둡니다.
•
따라서 구현 해야 할 파트는 총 4개 입니다.

flag 파싱

•
- 또는 0 이 올 수 있습니다. 둘다 올 수 있습니다.
•
같은 문자가 여러개가 들어올수있습니다.
최종 값

width 파싱

•
0 으로 초기화해줍니다.
•
숫자가 오거나, * 이 올수있습니다.
◦
숫자 인 경우 atoi 하면 됩니다.
◦
* 인 경우 va_arg(ap, int) 로 값을 받아옵니다.
◦
이떄 값이 음수인경우
▪
flag 를 - 로,
▪
width 에는 절대값을 씌워 양수로 바꿉니다.
최종 값

precision 파싱

•
-1 로 초기화 해줍니다.
•
. 이 여러개 올 수 있습니다.
◦
0 으로 초기화 해줍니다.
◦
숫자가 오거나, * 이 올수있습니다.
▪
숫자 인 경우 atoi 하면 됩니다.
▪
* 인 경우 va_arg(ap, int) 로 값을 받아옵니다.
▪
이떄 값이 음수인경우
•
-1 로 초기화합니다.
최종 값

type 파싱

•
%cspdiuxX 중에 하나 올수있습니다.
•
만약에 없으면 오류이므로 다음 단계로 넘어가지 않습니다.
최종 값
주의! type 이 없는 경우 segfault 가 뜰수있습니다.

3-2. va_arg

•
va_arg 를 통하여 값을 읽습니다.
Search
va_arg 코드의 사본
type
코드
크기
값
va_arg(ap, unsigned int)
4바이트
0 ~ 42억
va_arg(ap, void *)
8바이트
0 ~ 엄청 큰 값
COUNT3
•
long long 으로 캐스팅해서 변수로 저장하고 다니면 편합니다.
•
long long 이 8바이트 이기때문에 오버플로우되든 언더플로우되든 일단 저장해놓고
•
다시 값을 써야할때 해당 타입으로 캐스팅해서 쓰면 됩니다.
•
예)
char *str = "test"; long long value; value = (long long)str; printf("%s", (char *)value); //정상 출력
C++
복사

3-3. 포장

•
최종 출력 형식은 다음과 같습니다.
[left_margin][sign][prefix][zero][value][right_margin]
C++
복사
•
위의 형식을 저장하기 위한 구조체를 선언합니다.
typedef struct s_box { int left_margin; //왼쪽 스페이스 개수 char sign; // - 출력 int zero; //출력할 0의 개수 int prefix; //0x 출력 여부 (0 or 2) long long value; //va_arg 값 int value_len; //va_arg 값의 길이 char base[20]; //진수 int base_len; //진수 int right_margin; //오른쪽 스페이스 개수 } t_box;
C++
복사
•
앞으로 content 를 다음과같이 정의하겠습니다.
content : [sign][prefix][zero][value] 최종 출력 : [left_margin][content][right_margin]
C++
복사
•
모든 변수를 0으로 초기화 합니다.
◦
ft_bzero(&content, sizeof(t_content));
•
먼저 value 에 위에서 va_arg 로 받은값을 대입합니다.
•
0 출력 로직(content)을 계산하고, 스페이스바 출력 로직(margin)을 계산하겠습니다.
•
type 에 따른 content 를 완성 시키도록 하겠습니다.
규칙 사전 지식 (참고)

type %, type c

Search
변수
값
type이 % 일떄 %, 아니면 그대로
flag 가 0 이고, flag 가 - 이 아닐때 zero = width - value_len
COUNT5

type s

type d, type i, type u

Search
이름
값
type이 d, i 이고, value 가 음수면 1
type이 d, i 이고, value 가 음수면 절대값씌워서 양수로
get_numberlen((unsigned long)value, 10) (음수 고려 안함) precision 이 0, value 가 0 이면 value_len = 0
"0123456789"
precision ≠ -1 이라면 zero = precision - value_len precision 이 -1이고, flag 가 0 이고, flag 가 - 이 아닐때, zero = width - value_len - sign - prefix
COUNT7

type x, type X, type p

Search
이름
태그
type 이 p 이면 2 아니면 0
그대로
get_numberlen((unsigned long)value, 16) precision 이 0, value 가 0 이면 value_len = 0
type이 X 라면, "0123456789ABCDEF" 아니면 "01234566789abcdef"
precision ≠ -1 이라면 zero = precision - value_len precision 이 -1이고, flag 가 0 이고, flag 가 - 이 아닐때, zero = width - value_len - sign - prefix
COUNT7

margin 계산

•
content 가 완성되었기 때문에 margin 부분만 계산하면 된다.
•
먼저 content의 전체 길이를 구한다.
•
content_len = content→sign + ft_max(content→zero, 0) + content→prefix + content→value_len
•
flag 가 - 인 경우
◦
right_margin = ft_max(flag→width - content_len, 0)
•
아닌경우
◦
left_margin = ft_max(flag→width - content_len, 0)
•
최종 출력 길이
◦
ft_max(flag→width - content_len, 0) + content_len

3-4. 출력

•
이제 이미 다 만들어놓은 content 구조체를 가지고 출력만 잘 하면 된다 !!
[left_margin][sign][zero][prefix][value][right_margin]
C++
복사
•
위의 순서대로 출력하면된다.
1.
left_margin 만큼 스페이스 출력
2.
sign 이 1 이면 - 출력
3.
prefix 가 2 이면 0x 출력
4.
zero 만큼 0 출력
5.
value 출력
•
%, c
◦
value 값 출력
•
s
◦
value 가 있으면 value를 value_len 만큼 출력
◦
없으면 "(null)" 을 value_len 만큼 출력
•
d i u x X p
◦
value_len > 0 일떄만
▪
base 와 base_len 에 맞춰서 putnbr
6.
right_margin 만큼 스페이스 출력

4. 예외

•
타입 캐스팅에 유의하세요!!

5. 보너스

•
하는중....