[ft_printf](6)길이옵션[l,h], 서식지정자(c, s)출력


이번 포스트는 (ft_printf)길이옵션[l,h], 서식지정자(c, s)출력 조건문 구현에 관한 내용입니다.




1️⃣ 자료형 길이옵션 추가하기[ h, hh, l, ll ]

% + length + 자료형data type
%hhi, %hhdsigned char
%hi, %hdsigned short
%li, %ldsigned long int
%lli, %lldsigned long long int

(1) set_form함수에 길이옵션함수 추가

  • 서식지정자의 길이옵션을 관리하는 함수set_lenthform_spec함수[서식지정자를 만나면 출력하는 함수]바로 앞에 위치시켜 서식지정자를 체크하기전에 길이옵션을 체크하도록 합니다.

< set_form함수 >

void set_form(va_list ap, const char **format, int *len)
{
	t_flag	fg = { 0, };
	set_flag(ap, &fg, format);
	set_lenth(&fg, format, len);
	form_spec(ap, *format, &fg, len);
	(*format)++;
}

(2) 길이옵션에 사용될 변수 구조체에 추가

  • 길이옵션을 사용하게 되면 다양한 자료형을 다룰 수 있는 변수가 필요합니다.
  • 또한 ' l ', ' h '의 개수를 기억하는 변수가 필요합니다.

< t_flag구조체에 추가된 요소 >

typedef struct flags
{
    /* 기존 요소 생략 */
    int data_length;
    char c;
    short s;
    long long int lli;
    unsigned long long int ulli;
}               t_flag;

(3) set_lenth함수 구현[ l , h 의 개수를 새주는 함수]

< set_lenth함수 >

void set_lenth(t_flag *fg, const char **format, int *len)
{
	while (**format == 'l' || **format == 'h')
	{
		if (**format == 'l')
			fg->data_length++;
		if (**format == 'h')
			fg->data_length--;
		(*format)++;
	}
}

(4) print_di함수에 길이옵션추가[ d, i자료형만을 출력하는 함수]

  • va_arg매크로 함수로 받아오는 long long int temp변수를 길이 옵션에 따라 다양한 자료형으로 받아올 수 있게 세분화시켰습니다.[ t_flag 구조체의 새로운 요소를 사용]
  • 버퍼오버플로우의 경우로 들어오는 경우가 있기 때문에 매개변수 포인터를 적절한 자료형으로 받아와야 합니다.

< 버퍼오버플로우 단순예 >

printf("%hd\n", 123456);
printf("%hhd\n", 1234);
/*-------출력-------*/
-7616
-46
  • va_arg(ap, char)va_arg(ap, short)의 방법으로 char형short형을 받을 수 있을까 생각할 수 있지만 사용하지 못합니다.[ 예전 표준상의 문제로 가변 인자 목록의 기본 자료형 인자들이 정수형은 int로 실수형은 double 승격됬습니다. ]
  • 그렇기 때문에 va_arg(ap, int)char형, short형의 변수로 직접 받아오도록 했습니다.

< 길이옵션 조건문 >

if (fg->data_length == -2)            // hhi, hhd
    {
        fg->c = va_arg(ap, int);
        fg->lli = fg->c;
    }
    if (fg->data_length == -1)       // hi, hd
    {
        fg->s = va_arg(ap, int);
        fg->lli = fg->s;
    }
    if (fg->data_length == 0)        // i, d
        fg->lli = va_arg(ap, int);
    else if (fg->data_length == 1)    // li, ld
        fg->lli = va_arg(ap, long int);
    else if (fg->data_length == 2)    // lli, lld
        fg->lli = va_arg(ap, long long int);
    if (fg->lli < 0)
    {
        fg->ulli = fg->lli * (-1);
        fg->minus = 1;
        cnt++;
    }
    else
        fg->ulli = fg->lli;




2️⃣ 문자형(' c ')서식지정자 출력함수 구현

(1) 문자형c 서식규칙

printf("%c끝\n", 't');
printf("%3c끝\n", 't');
printf("%-3c끝\n", 't');
printf("%*c끝\n",3,'t');
printf("% c\n", 't');    // 컴파일 오류
printf("%03c끝\n", 't');  // 컴파일 오류
printf("%3.4c끝\n", 't'); // 컴파일 오류
/*-------출력-------*/
t끝
  t끝
t  끝
  t끝
  1. 너비 옵션을 사용이 가능합니다.
  2. ' - '플래그(왼쪽정렬) 사용이 가능합니다.
  3. ' * '옵션 사용이 가능합니다.

(2) 문자형(' c ')서식지정자 출력함수 구현

< print_c함수 >

int print_c(va_list ap, t_flag *fg)
{
    int cnt;

    fg->c = va_arg(ap, int);
    cnt = 0;
    while ((fg->left != 1) && (fg->padding_front - 1 > 0)) // 앞쪽너비
    {
        write(1, " ", 1);
        cnt++;
        fg->padding_front--;
    }
    write(1, &(fg->c), 1);         // 본문자출력
    cnt++;
    while ((fg->left == 1) && (fg->padding_front - 1 > 0)) // 뒤쪽너비
    {
        write(1, " ", 1);
        cnt++;
        fg->padding_front--;
    }
    return (cnt);
}




3️⃣ 문장형(' s ')서식지정자 출력함수 구현

(1) 문자형s 서식규칙

printf("%s끝\n", "hello");
printf("%7s끝\n", "hello");
printf("%-7s끝\n", "hello");
printf("%.3s끝\n", "hello");
printf("%.7s끝\n", "hello");
printf("%*.*s끝\n", 7, 3, "hello");
printf("% s끝\n", "hello");  // 컴파일 오류
printf("%0s끝\n", "hello"); // 컴파일 오류
/*-------출력-------*/
hello끝
  hello끝
hello  끝
hel끝
hello끝
    hel끝
  1. 너비 옵션을 사용이 가능합니다.
  2. ' - '플래그(왼쪽정렬) 사용이 가능합니다.
  3. ' * . * '옵션 사용이 가능합니다.
  4. ' . '(정밀도)문자열 최대출력크기 입니다.

(2) 문자열(' s ')서식지정자 출력함수 구현

< print_s함수 >

int print_s(va_list ap, t_flag *fg)
{
    int cnt;     // 총 출력할 문장길이
    int cnt2;    // 실제 출력할 문자열길이
    char* temp;

    temp = va_arg(ap, char*);
    cnt2 = ft_strlen(temp);
    if (fg->point == 1)    // [. ]정밀도 옵션이 있을시
        cnt2 = (cnt2 > fg->padding_back) ? fg->padding_back : cnt2;
    fg->padding_front -= cnt2;
    cnt = cnt2;
    while ((fg->left != 1) && (fg->padding_front > 0)) // 앞쪽너비
    {
        write(1, " ", 1);
        cnt++;
        fg->padding_front--;
    }
    write(1, temp, cnt2);       // 실제 문자열 출력
    while ((fg->left == 1) && (fg->padding_front > 0)) // 뒤쪽너비
    {
        write(1, " ", 1);
        cnt++;
        fg->padding_front--;
    }
    return (cnt);
}




© 2021.02. by kirim

Powered by kkrim