printf 함수를 재구현하는 ft_printf 프로젝트를 시작하면 서 들게 된 의문이 있다. printf를 사용하면서 우리는 자연스럽게 printf("%d * %d = %d", 3, 5, 3*5)
라고 쓰고 있다. 가만보면 printf라는 함수는 인자를 1개만 넣어도 되고, 2개만 넣어도 되고, 3개, 4개 그 이상을 넣어도 문제없이 돌아간다.
이것을 가능하게 하는 가변 인자에 대해 정리해보았다.
아래 sum 함수의 두 번째 인자로 사용되는 ...
이 가변 인자 혹은 가변 파라미터라고 불리는 것이다. 매개변수로 아무것도 넘겨주지 않을 수도 있고, 혹은 여러 개를 넘겨줄 수도 있다. 이러한 매크로는 함수가 고정된 수의 필수 인수에 가변 수의 선택적 인수가 붙은 형식을 사용한다고 가정한다.
#include <stdio.h>
#include <stdarg.h>
int sum(int count, ...)
{
int res = 0;
va_list ap;
int i;
va_start(ap, count);
for(i=0; i<count; i++)
res += va_arg(ap, int);
va_end(ap);
return res;
}
int main()
{
printf("%d\n", sum(10, 1,2,3,4,5,6,7,8,9,10));
return 0;
}
출력 결과 >> 55
각 가변 인자의 시작 주소를 가리킬 포인터이다.
void va_start(va_list ap, variable_name);
va_list
로 만들어진 포인터에게 가변인자 중 첫 번째 선택적 인수(variable_name)의 주소를 가르쳐주는 중요한 매크로이다. va_arg(), va_copy(), va_end()에 대한 후속 호출에 대해 ap 포인터를 초기화한다.
va_list
로 만든 포인터가 담긴다. void va_copy(va_list dest, va_list src);
va_start()를 dest에 적용한 후 src의 현재 상태에 도달하는 데 이전에 사용된 것과 동일한 순서로 va_arg()를 사용한 경우와 같이 dest를 src의 사본으로 초기화한다. va_copy() 또는 va_start()는 동일한 dest에 대한 va_end()의 중간 호출 없이 dest를 다시 초기화하도록 호출해야 한다.
var_type va_arg(va_list ap, var_type);
ap로 지정된 위치에서 지정된 var_type 값을 검색하고 리스트에서 다음 인수를 가리키도록 ap 를 증가 시켜 다음 인수가 시작 되는 위치를 결정한다. 즉, 특정 가변인자를 가리키고 있는 va_list
의 포인터를 다음 가변인자로 이동시켜 주는 매크로이다.
va_list
로 만든 포인터가 담긴다.int
나 long
, double
과 같은 타입 이름이 담긴다.var_type을 설정할 때 char, short 의 경우에는 int로 대신 쓰고, flaot의 경우에는 double로 대신 쓴 이후 형 변환을 해주어야 한다.
ex) char ch = (char) va_arg(ap, int);
void va_end(va_list arg_ptr);
모든 인수가 검색 된 후 va_end 는 포인터를 NULL로 다시 설정 한다. 즉, 사용한 가변인자 변수를 끝낼때 사용.
va_arg() 함수는 현재 인수를 리턴한다. va_copy(), va_end(), va_start() 함수는 값을 리턴하지 않는다.