우리는 지금까지 인자의 개수를 한정지어 프로그램을 작성하였다.
int func_1(int, int, int); int func_2(int, char *, float); int func_3(char, char, char, char*); |
인자의 개수가 늘었다 줄었다 할 수 있는 함수를 작성할 수 있도록 도와주는 것이 가변인자이다. 인자의 개수 뿐만 아니라 인자의 형(type)도 상관없다.
① 가변 인자 사용 단계
ⓐ 함수의 원형 정의
인자 리스트에 "..."을 사용한다.
int func(int, ...); |
가변 인자에 해당하는 부분에 점을 세 개 나열하면 된다. int는 고정된 것이고 "..."부분이 가변 인자가 된다.
main() ... |
ⓑ 함수의 본체 작성
본체는 원형을 선언한 것과 크게 다르지 않다. 단지 원형에서는 생략했던 변수명을 본체에서는 사용해야 한다는 것 뿐이다.
int func(int count, ...) { ... } |
ⓒ 헤더 파일 포함
#include<stdarg.h> |
② 가변 인자를 위한 매크로
가변 인자를 위한 매크로는 3가지만 알면 충분하다.
1. void va_start(va_list list, last); 2. type va_arg(va_list list, type); 3. void vaend(va_list list); |
ⓐ void va_start(va_list list, last);
va_start() 함수는 list를 초기화한다. 초기화한다는 의미느 포인터를 맨 처음으로 돌리는 의미가 있다.
(만약 이 함수가 없다면 va_arg()를 이용하여 인자들을 다 사용했을 때 처음으로 되돌릴 방법이 없게 된다.)
va_list는 헤더파일에 다음과 같이 선언되어 있다.
typedef void *va_list; |
- va_list list
va_list는 void형 포인터이다. void형 포인터를 아무것도 지정할 수 없는 포인터로 오인하면 안 된다. va_list가 void형 포인터로 선언되어 있기 때문에 어떤 형(type)도 사용할 수 있다.
- last
함수에 전달되는 마지막 고정 인자를 뜻한다.
ⓑ type va_arg(va_list, type);
고정 인자를 제외한 나머지 인자들을 얻기 위하여 사용된다. 보통 for()문을 이용하여 처리한다. va_arg()을 사용할 때마다 list의 포인터는 하나씩 증가하기 때문에 인자로 넘어 온 값들을 읽어 들일 수 있게 된다. type은 인자로 넘어오는 형(type)을 지정하면 된다.
ⓒ void va_end(va_list list)
가변 인자의 사용을 끝낼 때 사용한다. 보통 사용하지 않는다.
③ 가변 인자의 사용
가장 이해하기 쉬운 add()라는 함수를 작성해보자. 이 함수는 다음과 같이 작동한다.
add( 2, 7, 3); add( 5, 34, 35, 96, 15, 27); |
7과 3을 더해서 값을 리턴하고 34, 35, 96, 15, 27을 더해서 값을 리턴하는 함수이다. 가장 앞에 있는 인자는 나머지 인자의 개수이다.
예제는 add()함수를 이용하여 인자의 값을 더하고 이를 리턴하여 출력하는 프로그램이다.
#include<stdio.h> #include<stdarg.h> main() { int add(int, ...); int sum; sum = add(2, 284, 945); printf("%d\n", sum); sum= add(5, 456, 74, 24, 826, 34); printf("%d\n", sum); } int add(int count, ...) { va_list list; int sum =0; int i; va_start(list, count); for(i=0;i<count;i++) sum+=va_arg(list, int); va_end(list); return sum; } [출력결과] 1229 1414 |
count가 인자의 개수를 받아들여 for()문에서 이를 이용하고 있다. 정수형 인자들을 받아 들이고 있기 때문에 va_arg()에서 int를 사용하고 있다.
④ 주의사항
가변 인자를 사용하면서 주의해야 할 사항이 있다. 이것은 권유 사항이 아니라 반드시 지켜야 하는 사항이다.
1. va_start()를 사용하려면 적어도 하나 이상의 고정 인자가 있어야 한다. 즉, 다음과 같은 형식은 에러를 일으킨다.
int func(...); |
func()를 가변 인자의 집합으로만 선언할 수 없다. 반드시 func()는 하나이상의 고정 인자가 필요하다. printf()문을 보면 항상 맨 앞의 인자는 문자열을 전달하고 있음을 알 수 있으며 좋은 본보기에 해당한다.
printf("%s", imsi); |
printf()의 첫번째 인자를 이용하여 뒤이어 나오는 인자의 개수를 예측할 수 있는데, 첫번째 문자열 안에 있는 '%' 기호가 이 예측을 가능하게 한다.
출처: 다시 체계적으로 배우는 C언어 포인터(정보문화사:정재은 저)
#include <stdio.h>
#include <stdarg.h>
void foo(int n, ...)
{
va_list ap;
int sum = 0;
int i;
va_start(ap,n);
for(i=0;i<n;i++)
{
sum+=va_arg(ap,int);
}
va_end(ap);
printf("%d\n",sum);
}
int main(void)
{
foo(5,1,2,3,4,5);
}