[ft_printf] 가변인자 ( variadic functions)

Cadet_42·2021년 7월 21일
0

ft_printf

목록 보기
2/6
post-thumbnail

💡 가변인자 (Variadic Functions)

가변인자라는 개념이 생소하여, printf과제를 할때 생긴 첫 의문점은 "ft_printf 과제를 수행하는데, 가변인자가 무엇인지, 그리고 가변인자를 왜 알아야 하는가?" 이었다.

  • printf 함수는 인자를 1개만 넣어도 작동하고, 2개를 넣어도 작동하고, 3개,4개 혹은 그 이상을 넣어도 잘만 작동한다. 여러개의 인자를 넣어도 함수가 작동하도록 가능하게 하는 인자를 가변 인자라고 한다.

  • printf, scanf처럼, 매개변수의 개수가 정해지지 않은 함수가 있으며, 함수에 들어가는 인자(argument)의 개수가 변하는것을 가변인자 (가변인수, variable argument)라고 함.

  • 함수에서 가변인자를 정의할때는 고정 매개 변수가 한개 이상 있어야하며, 고정 매개변수 뒤에 ...을 붙여 매개변수의 개수가 정해지지 않았다는 표시를 해준다. 단, ... 뒤에는 다른 매개변수를 지정할 수 없다.

  • printf 함수의 원형은 하기와 같다.

printf format [arguments, ...]

💡 가변 인자 함수 만들기 variable argument lists

#include <stdarg.h>

The called function must declare an object of type va_list which is used by the macros va_start(), va_arg(), and va_end().

va_list ap: 가변인자 목록 포인터. 가변인자의 메모리 주소를 저장하는 포인터

  • ap (argument pointer)

va_start(ap, args): 가변인자를 가져올 수 있도록 포인터를 설정.

  • va_arg()을 사용하기 전에 va_start로 ap(arguemt pointer)를 declare 해줘야 한다.
    The va_start() macro initializes ap for subsequent use by va_arg() and va_end(), and must be called first.

va_arg (ap, type) : 가변인자 포인터에서 특정 자료형 크기만큼 값을 가져옴.

  • va_arg() 매크로를 부를때마다, ap는 next argument로 움직인다.
  • The argument ap is the va_list ap initialized by va_start(). Each call to va_arg() modifies ap so that the next call returns the next argument.
  • 💡 ap 가변인자 포인터 타입에 따라, type에 int , char * 등을 넣어준다. 💡

va_end(ap) : 가변인자 처리가 끝났을때 포인터를 NULL로 초기화.

✏️ void 함수로 만드는법

  • void 함수로 만들때는, void 함수 안에 printf()를 넣어 줌으로써, main함수에는 반환값 자료형 함수이름만을 호출하도록 하였다.
#include <stdio.h>
#include <stdarg.h> // va_list, va_start, va_arg, va_end 가 정의된 헤더파일

// void function으로, printf를 포함하여  variadic function을 만드는  방법
void printNumbers(int args, ...) // 가변 인자의 개수를 받음, ...로 가변 인자 설정
{
	va_list ap; // 가변 인자 목록 포인터 (ap : argument pointer)

	va_start(ap, args); // 가변 인자 목록 포인터 설정
	for (int i = 0; i < args ; i++) //args 가변 인자 개수 만큼 반복
	{
		int num = va_arg(ap, int); // int 크기만큼 가변 인자 목록 포인터에서 값을 가져옴, ap를 int 크기만큼 순방향으로 이동
		printf("%d", num); // 가변 인자 값 출력
	}
	va_end(ap); // 가변 인자 목록 포인터를 NULL로 초기화
	printf("\n"); // 줄바꿈
}

int main(void)
{
	printNumbers(1, 10);
	printNumbers(2, 10, 20);
	printNumbers(3, 10, 20, 30);
	printNumbers(4, 10, 20, 30, 40);
	return (0);
}

🔨 실행결과

10
10 20
10 20 30
10 20 30 40 

💡 가변 인자 step by step

step 1.

va_list ap; // 가변 인자 목록 포인터
va_start(ap, args); // 가변 인자 목록 포인터 설정 

va_start로 ap준비 (ap 는 argument pointer)

step 2.

이제 반복문으로 가변 인자 개수만큼 반복하면서 va_arg 매크로로 값을 가져오면 된다.
이때 va_arg에는 가변 인자의 자료형을 지정해 준다.

for(int i = 0; i < args; i++)  // 가변 인자 개수만큼 반복
{	
	int num = va_arg(ap, int); // int 크기만큼 가변 인자 목록 포인터에서 값을 가져옴.
    				  // ap를 int 크기만큼 순방향으로 이동
    	printf("%d", num);    // 가변 인자 값 출력 
}

int num = va_arg(ap, int)를 실행하면 현재 ap에서 4바이트 (int 크기)만큼 역참조하여 값을 가져온 뒤 ap를 4바이트만큼 순 방향으로 이동 시킨다.

va_arg로 ap에서 값을 가져온 뒤 포인터 이동.
즉, 반복문에서 반복할 때마다 ap는 4 바이트만큼 순방향으로 이동하므로 10, 20, 30, 40을 순서대로 가져올 수 있다.

step 3.

마지막으로 va_end 매크로를 사용하여 ap를 null로 초기화한다.
(다른 플랫폼에서는 문제가 생길 수도 있으므로 호환성을 위해서 va_end로 마무리를 해주는것이 좋다.)

va_end(ap) 가변 인자 목록 포인터를 null로 초기화

✏️ int 함수로 만드는법

  • addNumbers(int args, ...) : 각각의 가변인자를 더해주는 함수
  • minNumbers(int args, ...): 각각의 가변인자를 -하여 더해주는 함수
#include <stdio.h>
#include <stdarg.h>

int	addNumbers(int args, ...)
{
	va_list ap;
	int i;
	int sum = 0;
	va_start(ap, args);
	for(i = 0; i < args ; i++)
		sum+= va_arg(ap, int);
	va_end(ap);
	return (sum);
}


int minNumbers(int args, ...)
{
	va_list ap; 
	int i;
	int min = 0;

	va_start(ap, args);
	for (i = 0; i < args; i++)
		min-= va_arg(ap, int);
	va_end(ap);
	return (min);
}

int main(void)
{
	printf("the sum is : %d\n", addNumbers(3, 100, 200, 300));
	printf("the minus is :%d\n", minNumbers(3, 1, 2, 3));
	return (0);
}

🔨 실행결과

the sum is: 600
the minus is : -6

💡 Lessons learned

  • 가변인자란 무엇인지.
  • 가변함수가 어떻게 쓰이는지.

참고 출처 :

http://seyong.me/study/printf_sapjil/
https://42kchoi.tistory.com/13
https://dojang.io/mod/page/view.php?id=577
https://linux.die.net/man/3/va_arg

profile
안녕하세요! 개발공부를 하고 있습니다. 감사히 배우겠습니다. ;)

0개의 댓글