[ft_printf](7)서식지정자(u)출력, 새로운 출력함수
이번 포스트는 (ft_printf)서식지정자(u)출력, 새로운 출력함수에 관한 내용입니다.
1️⃣ 부호없는 10진수 서식지정자(u) 규칙
printf("%u끝\n", 1234);
printf("%8u끝\n", 1234);
printf("%+8u끝\n", 1234); //컴파일 오류
printf("% 8u끝\n", -1234); //컴파일 오류
printf("%-8u끝\n", 1234);
printf("%08u끝\n", 1234);
printf("%-08u끝\n", 1234); //컴파일 오류
printf("%8.6u끝\n", 1234);
printf("%-8.6u끝\n", 1234);
printf("%8.3u끝\n", 1234);
printf("%3.3u끝\n", 1234);
printf("%08.6u끝\n", 1234); //컴파일 오류
printf("%*.*u끝\n", 8, 6,1234);
printf("%0*u끝\n", 8, 1234);
1234끝
1234끝
1234 끝
00001234끝
001234끝
001234 끝
1234끝
1234끝
001234끝
00001234끝
- 너비옵션사용이 가능합니다.
- ' - '플래그(왼쪽정렬) 사용이 가능합니다.
- ' 0 '플래그 사용이 가능합니다.
- ' '플래그(공백)과 ' + '플래그 사용이 불가능 합니다.
- ' * . * '옵션 사용이 가능합니다.
2️⃣ 서식지정자(u) 출력함수 구현
- 서식지정자(u)는 d, i의 자료형에서
unsigned
만 적용해주고 기존의 print_di함수에 추가해 주었습니다.
(c == 'u') ? va_arg_u(ap, fg) : va_arg_di(ap, fg);
위와 같은 조건문을 만들어서 매개변수포인터로 부터 적절한 자료형을 받아오는 함수를 구현하였습니다.
(1) va_arg_di함수
void va_arg_di(va_list ap, t_flag *fg)
{
if (fg->data_length == -2)
{
fg->c = va_arg(ap, int);
fg->lli = fg->c;
}
if (fg->data_length == -1)
{
fg->s = va_arg(ap, int);
fg->lli = fg->s;
}
if (fg->data_length == 0)
fg->lli = va_arg(ap, int);
else if (fg->data_length == 1)
fg->lli = va_arg(ap, long int);
else if (fg->data_length == 2)
fg->lli = va_arg(ap, long long int);
if (fg->lli < 0) // 출력할 정수 분호 판별
{
fg->ulli = fg->lli * (-1);
fg->plus = '-';
}
else
fg->ulli = fg->lli;
}
(2) va_arg_u함수
void va_arg_u(va_list ap, t_flag *fg)
{
if (fg->data_length == -2)
{
fg->uc = va_arg(ap, int); //t_flag에 unsigned char 요소를 추가
fg->ulli = fg->uc;
}
if (fg->data_length == -1)
{
fg->us = va_arg(ap, int); //t_flag에 unsigned short 요소를 추가
fg->ulli = fg->us;
}
if (fg->data_length == 0)
fg->ulli = va_arg(ap, unsigned int);
else if (fg->data_length == 1)
fg->ulli = va_arg(ap, unsigned long int);
else if (fg->data_length == 2)
fg->ulli = va_arg(ap, unsigned long long int);
}
3️⃣ 출력함수 새롭게 구현하기
- 기존에 출력함수 출력한 문자수를 반환하도록 구현 했습니다.
- 한 글자만 출력할경우엔
write
함수를 이용해서 직접 출력 해주었습니다. - 하지만
%u
서식자 까지 구현한 지금 공통된 부분이 너무많아서 코드 길이가 쓸데없이 길어졌습니다.(42Seoul의 norm규칙은 함수의 길이도 제한하고 하고 있기 때문에 신경써야되는 부분입니다.) - 밑의 코드 예시의 경우를 새로운 출력함수를 구현하면 가독성면이나 코드 길이면에서 좋아질 것 같습니다.
(1) 한글자 출력하는 코드의 비슷한 패턴 예
- 아래와 같은 while문 출력함수가 반복적으로 사용됬습니다.
while (fg->padding_front > 0)
{
write(1, " ", 1);
fg->padding_front--;
cnt++;
}
(2) 새로운 출력함수 구현[ft_print_word함수]
int *len
의 변수를 직접적으로 변경해주는 함수입니다.- 플래그 카운트도 변경시켜줘야 하기 때문에 출력개수를 반환하도록 했습니다.
< 새롭게 구현된 ft_print_word함수 >
size_t ft_print_word(char c, int cnt, int *len)
{
int result;
result = 0;
while (cnt-- > 0)
{
write(1, &c, 1);
result++;
(*len)++;
}
return (result);
}
< *len값을 바꿈과 동시에 플래그 카운트를 변경해주는 사용 예 >
if(fg->minus == 1)
fg->padding_front -= ft_print_word(' ', fg->padding_front, len);
(3) 새로운 출력함수 구현[ft_print_str]
- 문자열을 출력할 때 이미 문자열의 길이를 알고 있었습니다. 그렇기 때문에 굳이
ft_print_str
함수 내부에서'\0'
(문자열끝)을 확인하는 반복문은 속도를 늦출뿐입니다. 또한 코드의 길이를 조금이나마 줄이기 위해*len
변수를 불러와서 직접적으로 증가 시켜줬습니다.
< 변경된 ft_print_str함수 >
void ft_print_str(const char *str, int cnt, int *len)
{
const char *temp;
temp = str;
while (cnt-- > 0)
{
write(1, temp, 1);
temp++;
(*len)++;
}
}
(4) 새로운 출력함수를 적용한 print_diu함수[%d, %i, %u 출력함수]
< print_diu함수 >
void print_diu(va_list ap, t_flag *fg, const char c, int *len)
{
char *result;
int cnt;
(c == 'u') ? va_arg_u(ap, fg) : va_arg_di(ap, fg);
result = ft_ullitoa_malloc(fg->ulli, DIGITS); // 정수->문자 변환
cnt = ft_strlen(result); // 출력할 문자길이
/* 앞,뒤 너비옵션이 출력문자길이보다 짧으면 의미가 없으므로 0으로 지정 */
fg->padding_front = (fg->padding_front > cnt) ? (fg->padding_front - cnt) : 0;
fg->padding_back = (fg->padding_back > cnt) ? (fg->padding_back - cnt) : 0;
if (fg->plus != 0)
fg->padding_front--;
if (fg->left != 1) // '-'왼쪽정렬이 아닐때
{
if (fg->zero == 1)
{
if (fg->plus != 0)
ft_print_word(fg->plus, 1, len);
fg->padding_front -= ft_print_word('0', fg->padding_front, len);
}
else if (fg->zero == 0)
{
fg->padding_front -= ft_print_word(' ', fg->padding_front - fg->padding_back, len);
if (fg->plus != 0)
ft_print_word(fg->plus, 1, len);
fg->padding_back -= ft_print_word('0', fg->padding_back, len);
}
}
else // '-'왼쪽정렬일 때
{
if (fg->plus != 0)
ft_print_word(fg->plus, 1, len);
fg->padding_front -= fg->padding_back;
fg->padding_back -= ft_print_word('0', fg->padding_back, len);
}
ft_print_str(result, cnt, len); // 서식지정자 출력 (메인 출력)
if(fg->left == 1) // 뒤쪽 공백출력 판단
ft_print_word(' ', fg->padding_front, len);
free(result); // ft_ullitoa_malloc함수 반환값 메모리 해제
}
(5) 새로운 출력함수를 적용한 print_c함수[%c 출력함수]
< print_c함수 >
void print_c(va_list ap, t_flag *fg, int *len)
{
fg->c = va_arg(ap, int);
if (fg->left != 1)
fg->padding_front -= ft_print_word(' ', fg->padding_front - 1, len);
ft_print_word(fg->c, 1, len); // 본문자 출력
if (fg->left == 1)
fg->padding_front -= ft_print_word(' ', fg->padding_front - 1, len);
}
(6) 새로운 출력함수를 적용한 print_s함수[%c 출력함수]
< print_s함수 >
void print_s(va_list ap, t_flag *fg, int *len)
{
int cnt; // 실제 출력할 문자열길이
char* temp;
temp = va_arg(ap, char*);
cnt = ft_strlen(temp);
if (fg->point == 1) // [. ]정밀도 옵션이 있을시
cnt = (cnt > fg->padding_back) ? fg->padding_back : cnt;
fg->padding_front -= cnt;
if (fg->left != 1) // 앞쪽너비
fg->padding_front -= ft_print_word(' ', fg->padding_front, len);
ft_print_str(temp, cnt, len);
if (fg->left == 1) // 뒤쪽너비
fg->padding_front -= ft_print_word(' ', fg->padding_front, len);
}