본문 바로가기

고급C,C++

[고급C언어] 가변인자

우리는 지금까지 인자의 개수를 한정지어 프로그램을 작성하였다.

int func_1(int, int, int);

int func_2(int, char *, float);

int func_3(char, char, char, char*);

func_1(), func_2()의 인자 개수는 3이고 func_3() 은 4이다. 이 둘을 하나의 함수로 재작성할 수 있을까?

인자의 개수가 늘었다 줄었다 할 수 있는 함수를 작성할 수 있도록 도와주는 것이 가변인자이다. 인자의 개수 뿐만 아니라 인자의 형(type)도 상관없다.

 

 

① 가변 인자 사용 단계

ⓐ 함수의 원형 정의

인자 리스트에 "..."을 사용한다.

  int func(int, ...);

가변 인자에 해당하는 부분에 점을 세 개 나열하면 된다. int는 고정된 것이고 "..."부분이 가변 인자가 된다.

 

main()
{
        int func(int, ...);

        ...
}

 

ⓑ 함수의 본체 작성

본체는 원형을 선언한 것과 크게 다르지 않다. 단지 원형에서는 생략했던 변수명을 본체에서는 사용해야 한다는 것 뿐이다.

 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);
}