42 본과정 과제로 나온 printf 재구현하기.
보자마자 와 어렵겠다 싶었다.
왜냐하면 get_next_line 에서 파일입출력 관련해서 배우면서 엄청나게 스트레스를 받았는데,
이번에는 va_list, va_start, va_arg, va_end 그리고 va_cpy 라는 개념을 새로 배워야 한다는 이유 때문이었다.

그래도 내가 libft 를 하나씩 깬 것처럼,
스트레스를 받으면서 get_next_line 을 결국 해낸 것처럼(아마도)
Printf 또한 끝낼 수 있을 것이고 끝내는 그 날을 위해 또 달려본다.
(우리는 언젠가 그것을 해결할 것이다. 늘 그랬듯이. 라는 광고문구가 떠오른다.)

일단 va_list 와 va_start 그리고 va_arg 부터 알아보자.
va_로 시작하는 함수들은 #include <stdarg.h>에 있다.

 

예를 들어 다음과 같은 함수가 있다 치자.

Void print_digit(int args, ...)
{
	va_list ap;                     // 가변 변수들을 가리킬 포인터이다.

	va_start(ap, args);             // ap라는 포인터가 args만큼 
                                    // 가변 변수들을 차례로 가리키게 만듬
	for (int i = 0 ; i < args; i++)
	{
		int num = va_arg(ap, int);	
        // 윗줄에서 va_arg는 int byte만큼 포인터를 이동시키면서 읽은 정보를 반환함.

		printf("%d\n", num); // 이 함수는 인자로 들어온 정수를 출력한다.
	}
	va_end(ap);
}



이 경우 인자로 받은 args는 가변 인자의 개수이다.
여기서 말하는 가변 변수란 호출할 때마다 그 개수가 달라지는 인자다.
다음 예제를 보면 더 잘 이해가 갈 것이다.

int main()
{
	print_digit(1, 10);
	print_digit(2, 10, 20);
	print_digit(3, 10, 20, 30);

	return (0);
}

출력 결과 :
10
10 20
10 20 30

그림으로 살펴보면 다음과 같이 작동한다.

여기서 살펴본 예제에서는 int형으로 인자가 들어왔다.

그런데 우리는 const char *형식으로 받을 것이다.

char *형식에서는 어떻게 처리를 해줘야 하는지 한번 보자.

 

여기서는 다음의 세 개 형태를 처리해볼 것이다

: d(int) / c(char) / s(char *)

 

void print_dcs(char *dcs, ...)
{
	va_list ap;    //가변 인자 목록을 ap에 담을 것이다.
    size_t i = 0;
    
    va_start(ap, dcs);	//dcs라는 문자열의 개수 만큼 ap가 이동할 것.
    while (dcs[i] != '\0')
    {
    	if (dcs[i] == 'd')
        	printf("%d ", va_arg(ap, int));
        if (dcs[i] == 'c')
        	printf("%c ", va_arg(ap, char));
        if  (dcs[i] == 's')
        	printf("%s ", va_arg(ap, char *));
        i++;
    }
    va_end(ap);     //ap가 NULL을 가리키도록 만든다.
                    //end는 안정성을 위해 써주도록 한다.
    printf("\n");    
}

int main()
{
    print_dcs("d", 10);                    // 정수
    print_dcs("dc", 10, 'a');              // 정수, 문자
    print_dcs("dcs", 10, 'a', "Hello42");  // 정수, 문자, 문자열
    
    return (0);
}

결과 :
10
10 a
10 a Hello42

먼저 print_dcs가 인자로 char *을 받는 이유는 우리가 일반적으로 printf를 사용할 때에도

printf("something%something", ~);

이런 식으로 문자열을 넣기 때문이다.

 

위 예제에서 print_dcs("dcs", ~);

이런 식으로 명령을 내리면 print_dcs 함수 내부에서 va_start(ap, dcs)는

char * 형태로 들어온 dcs의 길이를 구해서(==3) ap가 그것 만큼 포인터를 이동시키도록 만든다.

 

우리가 사용한 것과 같이 print_dcs("dcs", 10, a, Hello42)를 예로 들어 설명해보겠다.

 

 

'Code 42 > ft_printf' 카테고리의 다른 글

printf 재구현하기 part3. pseudo-code  (0) 2020.06.29
printf 재구현하기 part 2.  (0) 2020.06.29
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기
// custom