가변인자라는 개념이 생소하여, printf과제를 할때 생긴 첫 의문점은 "ft_printf 과제를 수행하는데, 가변인자가 무엇인지, 그리고 가변인자를 왜 알아야 하는가?" 이었다.
printf 함수는 인자를 1개만 넣어도 작동하고, 2개를 넣어도 작동하고, 3개,4개 혹은 그 이상을 넣어도 잘만 작동한다. 여러개의 인자를 넣어도 함수가 작동하도록 가능하게 하는 인자를 가변 인자라고 한다.
printf, scanf처럼, 매개변수의 개수가 정해지지 않은 함수가 있으며, 함수에 들어가는 인자(argument)의 개수가 변하는것을 가변인자 (가변인수, variable argument)라고 함.
함수에서 가변인자를 정의할때는 고정 매개 변수가 한개 이상 있어야하며, 고정 매개변수 뒤에 ...
을 붙여 매개변수의 개수가 정해지지 않았다는 표시를 해준다. 단, ...
뒤에는 다른 매개변수를 지정할 수 없다.
printf 함수의 원형은 하기와 같다.
printf format [arguments, ...]
#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
: 가변인자 목록 포인터. 가변인자의 메모리 주소를 저장하는 포인터
va_start(ap, args)
: 가변인자를 가져올 수 있도록 포인터를 설정.
va_arg (ap, type)
: 가변인자 포인터에서 특정 자료형 크기만큼 값을 가져옴.
ap
가변인자 포인터 타입에 따라, type에 int
, char *
등을 넣어준다. 💡 va_end(ap)
: 가변인자 처리가 끝났을때 포인터를 NULL로 초기화.
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
va_list ap; // 가변 인자 목록 포인터
va_start(ap, args); // 가변 인자 목록 포인터 설정
va_start로 ap준비 (ap 는 argument pointer)
이제 반복문으로 가변 인자 개수만큼 반복하면서 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을 순서대로 가져올 수 있다.
마지막으로 va_end
매크로를 사용하여 ap를 null로 초기화한다.
(다른 플랫폼에서는 문제가 생길 수도 있으므로 호환성을 위해서 va_end
로 마무리를 해주는것이 좋다.)
va_end(ap)
가변 인자 목록 포인터를 null로 초기화
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