[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);
}




© 2021.02. by kirim

Powered by kkrim