https://dojang.io/mod/page/view.php?id=736
전체 모양
%[플래그][넓이][.(정밀도)][길이]서식지정자
플래그
# : 진법에 맞게 0, 0x, 0X를 붙임
0 : 플래그인데 공백을 0으로 채움
- : 왼쪽정렬
(space) : 양수면 스페이스 하나, 음수면 - 출력,
+ : 양수면 무조건 플러스 기호 추가 음수면 -출력. + 플래그가 공백보다 우선순위가 높다.
넓이
넓이는 그냥 폭을 지정해주는것
정밀도
정밀도는 서식지정자마다 뜻이 다르다. 얼마나 정밀한 데이터를 출력할것인지에 대한것
정밀도가 음수인 경우 세팅되지 않은것과 같다.
0인경우는 세팅된것이라고 볼 수 있음
길이
각각의 서식지정자의 자료형이 달라짐 (리턴할때만 확인해주면 될듯)
길이에서 주의할점은 길이옵션중에 가장 큰 길이옵션만 반영되는것이다.
서식지정자 : cspdiuxX%nfge (이건 데이터 처리할때 다시확인)
기타
* : 파라미터로 하나 전달받아서 그걸로 정밀도나 넓이로 사용한다.
. : 뒤에 오는건 무조건 정밀도
특징
1. printf는 %를 절대 문자로 보지 않는다. 그래서 %를 출력하기 위한 %% 를 지원하고 있고, \%를 입력한다 해도 문자열 자체에서 %를 위한 특수문자 이스케이핑 처리를 해주지 않기 때문에 아무것도 출력되지 않는다.
2. 플래그, 넓이, 정밀도, 길이는 순서 상관없음
3. 숫자는 정밀도와 넓이에서만 사용된다. .뒤의 숫자는 무조건 정밀도이고, 그 외의 위치에서 사용되는 숫자는 무조건 넓이이다.
4. 플래그, 정밀도, 넓이, 길이는 맨 마지막에 온 값만 세팅된다.
5. 실제 printf는 전체 스트링을 모아서 한꺼번에 출력하지만 ft_printf는 바로바로 출력한다. (인것같음)
6. 서식지정자가 아닌경우?
그냥 그 한글자를 %서식지정자처럼 바로 출력하면된다.
--------------------------------
0. 함수 몸통 문자열, 파라미터들을 전달받음
함수로 전달해줘야되기 때문에 va_start를 여기서해야됨.
반복문 시작!!
옵션 저장할 변수 생성
1. 문자열 서식지정자 파싱 (파싱함수)
인자는 문자열, 리턴할 포인터변수
시작인덱스 기억 (하나 처리하고 다시 들어왔을때 사용해야되기 떄문)
1-1) 문자열 쭉 읽으면서 %가 아니면 출력
1-2) %가 나오는 순간 파싱 시작
내부에서 반복문 또 돌면서 전체 함수를 한번씩 호출.
플래그, 넓이, 정밀도, 길이를 계속해서 업데이트 해주고 더이상 없다면 서식지정자
index변수 주소값 넘겨서 계속 사용하기.
서식지정자가 완성되지 않고 함수가 종료되면 그냥 출력하지도 않는다.
서식지정자가 완성된다면 출력함수로 전달
2. 처리과정 (인자로 받은 데이터 문자열 생성)
일단 문자열을 만들긴 해야됨.
2-0. %, c, 그외
서식지정자를 한글자 출력
정밀도의 의미가 없다. 폭 -1만큼 스페이스바 또는 0플래그인경우 0으로 채운 뒤 서식지정자 한글자를출력한다
0, -, 넓이만 의미가있다.
0 플래그가 세팅된 경우 width-1 크기의 0만큼 출력 후 한글자 출력
- 플래그가 세팅된경우 한글자 출력 후 공백으로 출력(왼쪽정렬). 0플래그가 세팅되어있어도 뒷부분은 0으로 출력하지 않음
printf("[%-06.10000c]\n", 'a');
-> [a ]
가 아니라 길이까지 의미가 있다.
%lc는 유니코드 문자를 출력하기 위한 wint_t 형 데이터이다.
wint_t c = L'X';
자세한건 -> https://parktest0325.tistory.com/285?category=958062
리턴값은 유니코드한개당 유니코드가 저장된 wint_t의 크기인 4byte가 출력된다.
2-1. s
width : 최소 너비. width가 출력할 문자열보다 작은경우는 무시, 문자열보다 큰경우에만 공백 추가
prec : 찐 문자열을 최대 어느정도까지 출력할건지에 대한 옵션
여기도 마찬가지로 l옵션이 유니코드 문자열 출력하는 옵션이다.
printf("%s\n", str);
printf("%010s\n", str);
printf("%010.2s\n", str);
printf("%-010.2s\n", str);
printf("%.20s\n", str);
L"가나다라" 를 인자로 줬을때 한글은 각각 3byte인데, 정밀도를 4 또는 5로 주면 '가' 라는 글자만 출력되며, 출력된 바이트가 3byte였기 때문에 width에 10을 줘도 0은 7개가 출력된다. 이 부분을 유의해서 짜면된다.
printf("[%010.4ls]\n", L"가나다라");
-> [0000000가]
2-2. d, i, u, x, X
d, i 는 scanf를 사용할땐 전달한 파라미터를 10진법으로만 읽을건지, 아니면 앞에 진법표시에 따라 011 같은 경우에는 8진법으로 읽을것인지 선택하는 서직지정자이다.
d, i 는 signed, u,x,X는 unsigned 형으로 출력한다.
일단 출력할 숫자의 길이를 알아야 width 를 얼마나 할당할지 알 수 있기 때문에 숫자가 몇자리인지 먼저 확인하는 함수가 필요하다.
맨처음에 길이를 구할때부터 d, ld, lld, unsigned인지에 따라 가져온 값을 몇으로 봐야하는지 정해야하기 때문에 처음에 msb를 세팅하고, 음수(플래그는 d, i일때만)인지 확인해서 음수인 경우엔 -1을 곱해서 양수로 만들고 형변환을 해줘야한다.
long long ft_type(long long l, t_opt opt)
{
if (opt.length == LENGTH_HH)
return ((char)l);
else if (opt.length == LENGTH_H)
return ((short)l);
else if (opt.length == LENGTH_L)
return ((long)l);
else if (opt.length == LENGTH_LL)
return ((long long)l);
else
return ((int)l);
}
타입 형변환은 그냥 지금 들어온 값을 그대로 원하는 타입의 똑같은 값으로 리턴해주는건데,
이렇게 보내더라도 받는 함수는 longlong타입이라 -1 값이 들어오는 경우 longlong의 -1 (=0xFFFFFF....)로 채워진다.
이걸 방지하기 위해 필요한 바이트 이외에는 삭제시키는 코드가 필요하다.
오버플로우 이름을 가진 함수지만 사실 비트연산을 이용해 해당 비트 이상은 버리는 함수임
void ft_byte_overflow(long long *l, t_opt opt)
{
if (opt.length == LENGTH_HH)
*l = *l & 0xFF;
else if (opt.length == LENGTH_H)
*l = *l & 0xFFFF;
else if (opt.length == LENGTH_L)
*l = *l & 0xFFFFFFFFFFFFFFFF;
else if (opt.length == LENGTH_LL)
*l = *l & 0xFFFFFFFFFFFFFFFF;
else
*l = *l & 0xFFFFFFFF;
}
패딩 출력은 -가 있다면 -까지 패딩 길이에 들어간다.
노플래그 : +는 그냥 패딩, -는 하나 출력
space : +는 공백, -는 - 출력
+ : +는 +, -는 - . + 플래그가 공백보다 우선순위가 높다.
# : 0x도 패딩에 들어감
X, x 는 : #플래그로 나오는 0x 대소문자로 만들어야함
부호는 맨앞에 나와야한다
결국 아래와 같은 순서가 된다.
부호 출력
만약 부호가 있는경우 맨앞에 출력 (정밀도가 세팅되어있다면 부호는 패딩과 정밀도 중간에 출력해야함)
정밀도 : 0플래그 무시됨. 필수로 출력해야되는 숫자. 정수는 0으로 채워짐
너비 - 출력숫자 - 정밀도 만큼 패딩 출력 (근데 정밀도가 음수인경우도 있음 이걸 주의해야한다.)
정밀도 - 출력숫자 만큼 정밀도 (‘0’) 출력
마이너스 플래그
정밀도 - 출력숫자 만큼 ‘0’ 출력
너비 - 출력숫자 - 정밀도 만큼 패딩 출력
2-3. p
그냥 주소값 받은걸 length=LL, format=x로 두고, flag에 #을 추가해서 정수출력하면 된다.
2-4. n
int *에 지금까지 출력한 문자의 개수를 넣어줌.
l ll h hh 길이에 따라서 다른 사이즈로 저장해야 하기 때문에
2-5. f, e
실수표기 1.200000
정밀도 : 소수점 몇자리까지 출력할것인지? -1이하는 전부 세팅안된것. 0은 정수부분만 출력. 기본값 = 6
정밀도에서 마지막출력은 반올림해야한다.
너비 : ., 부호까지 포함해서 패딩을 넣으면됨
부동소수점 출력 : https://parktest0325.tistory.com/291
정수부와 소수부를 나눠서 세팅해주는 함수를 만들어서
% 연산을 사용할 수 없기 떄문에 정수부 / 10 한 값에서 소수부를 가져와서 *10 하면 된다.
e 서식 : 실수를 e 표기법으로 표기. 1.200000e+00
f랑 e는 비슷한 로직으로 만들어야한다.
f 를 출력할때 그냥 exp를 1로 해서 전달하면 출력되도록 해야한다. 그리고 실제 exp는 10진수화 시켜서 e+xx 형식으로 만든다.
f 결과를 담은 문자열 배열에서
idx를 ++ 하면서 소수점을 이동시킨다. (스왑)
이동시킨 후 몇번 이동시켰는지를 e%+.2d, num 으로 출력한다.
======
만들때 그냥 소수점 없이 문자열을 만들어두고, 소수점까지만 문자열출력 + '.' + 이후문자열 출력
이런식으로 하는게 좋다. 왜냐하면 e옵션을 지정할때 .을 만들어두면 계속 .의 좌표를 옮겨줘야 하기때문이다.
그리고 반올림 할떄도 그냥 조건 추가없이 앞으로 넘기면되기떄문
=====
수정할 사항
prec가 엄청 크게 들어왔을때를 생각해서 출력하고 남은부분은 전부 0으로 출력해야한다.
2-7. g
e 나 f중 짧은것으로 표기
숫자값의 절대치가 너무 커서 precision의 자리수를 넘는 경우와 숫자값의 절대값이 0.0001보다 작은 경우 e형식이 사용되어짐. 그 외의 경우는 f형식으로 사용됨
=> e-5 부터 또는 e+prec부터
일반적인 e, f랑 다른점이 있다. 시작위치에서 0을 제외하고 prec를
일단 함수 하나 써서 조건에 맞으면 옵션 구조체 세팅하고 출력하면 될듯하다
!!!될줄알았지만
지멋대로인부분이 많다.
어떨땐 반올림하고 어떨떈 안하고 어떨땐 e표기법 쓰고 어떨땐 안쓰고
뭐임?
3. 출력함수
문자열을 만들었기 때문에 길이가 어느정도인지 이미 알수있고 width나 prec로 인한 0또는 스페이스바의 길이를 미리 알수있다.
정밀도가 세팅된경우, 패딩 -> 부호 -> 정밀도 -> 숫자 순서 출력이고, 세팅되지 않고 0 플래그가 세팅된 경우에는 부호 -> 패딩 -> 숫자 순서다. 0플래그가 세팅되지 않은 경우에는 패딩 -> 부호 -> 숫자 순서로 출력된다.
값은 바로바로 출력하기 때문에 동적할당을 사용할 필요가 없고, 출력한 수만큼 값을 리턴해서 메인함수의 리턴값으로 전달해야 한다.
--------------------------------------------------
에러처리
패턴이 일치하지 않는경우 그냥% 무시.
서식지정자가 적은경우
서식지정자가 많은경우 그냥 무시하면될듯. fsb가 그래서 발생하는거아님?
유니코드 출력을 위한 locale 설정
#include <locale.h>
setlocale(LC_ALL, ""); // 컴퓨터의 지역 설정을 따름
// 또는
setlocale(LC_ALL, "Korean"); // 한국
'42 Seoul' 카테고리의 다른 글
맥 디버깅 관련 (0) | 2021.06.12 |
---|---|
C 언어 가변인자 사용법 (0) | 2021.06.12 |
Ruby on Rails - 여러 기능이 있는 페이지 만들기 (0) | 2021.06.07 |
Ruby on Rails Piscine (0) | 2021.05.24 |
netwhat (0) | 2021.05.20 |